以前,我们都把对数据库的增删改查语句写在xml文件中(详见:《程序员成长笔记(一)》第三部分,第四章,第四节)。
由于Java注解的简洁高效,在Java注解的思想(干掉xml)下,现在越来越多的人使用java注解来进行增删改查操作。
而且MyBatis3也支持并鼓励我们使用Java注解来进行CRUD操作。
注:CRUD即:增Create、查Retrive、删Delete、改Update。
下面以示例进行说明
本例子的软硬件环境:
Windows7、Eclipse(Oxygen.3a Release)、Jdk1.8、MyBatis(3.4.5)、SpringBoot(2.0.1.RELEASE)、MySQL。
一级颜色:绿色 二级颜色:黄色 注意事项:红色 插入说明:蓝
增@Insert
先给出MySQL数据库中的相关employee表
增(简单增)示例:
数据访问层中的查询语句示例:
注:如果参数只有一个,那么可以直接#{属性名}进行属性值获取,如果有多个参数,必须使用@Param指明。
增(同时获取主键)方式一:
注:如果只有一个参数的话,那么可以不使用@Param,此时#{xxx}和keyProperty = “xxx”中的xxx可以直接写实体类模型的属性名。
注:如果有多个参数,那么我们需要使用@Param来进行指明,当然也推荐一个参数时也使用@Param注解。如果使用@Param指明参数了,且在注解中使用到了该参数的某些值时,一定要指明是该参数的。
如:这里的keyProperty = “e.id”是可以的;而keyProperty = “id”不可以。
增(同时获取主键)方式二:
注:方式二的注意事项与方式一一样。
增(既有实体参数,又有普通参数):
注:使用注解CRUD时,可以多个参数,这些参数可以是普通参数,也可以是复杂参数。
注:使用自动获取主键@Options或@SelectKey能正常获取到该对象插入数据库表中后的主键。
删@Delete
先给出MySQL数据库中的相关employee表
删(简单删)示例:
改@Update
先给出MySQL数据库中的相关employee表
改(简单改)示例:
查@Select
先给出MySQL数据库中的相关employee表
简单查(以“一般”类型 接收数据)示例:
数据访问层中的查询语句示例一:
数据访问层中的查询语句示例二:
简单查(以 对象模型 接收数据)示例:
数据访问层中的查询语句示例:
注:id = true出现在哪里,就说明那个参数是主键。
如:
就说明idCard是主键。
注:如果接收查询结果的,是一个对象模型,那么程序是通过对应的有参构造或则无参构造+setter方法,将结果放进实体类模 型的。
即:这就要求我们,在创建实体类模型时,一定要创建有对应的有参构造或无参构造+setter方法。
注:如果column名字与property不一致,那么需要在Result中指出来。
简单查(以 Map<String, Object> 接收数据)示例:
简单查(以 集合类型 接收数据)示例:
示例一:
示例二:
注:如果查询结果横跨多个实体模型,那么我们使用List来接收数据。
动态语句:
我们都知道如何在xml中处理动态的SQL语句,那么使用Java注解如何处理呢?需要使用@xxxProvider,并指定(经过逻辑处理后)返回SQL语句的方法,以及该方法所在的类。
注:使用@xxxProvider时,就不要使用@Param了,否者容易出错。
注:xxx为Insert、Update、Delete、Select。
注:这些(代理)方法最好不要重载,避免不必要的问题。
注:我们可以单独创建一个package、创建一个类来放置这些方法,如:
动态增@InsertProvider
单个参数:
数据访问层中的方法示例:
注:@InsertProvider需要指定(经过逻辑处理后)返回SQL语句的方法,以及该方法所在的类。
给出逻辑处理方法示例:
多个参数:
数据访问层中的方法示例:
注:@InsertProvider需要指定(经过逻辑处理后)返回SQL语句的方法,以及该方法所在的类。
给出逻辑处理方法示例:
注:如果数据访问层中的对应的方法有多个参数时,那么此方法的参数类型必须为Map<String,Object>;
注:此方法需要返回一个SQL字符串。
同时获得主键(获得主键的方式和@Insert是一样的):
获得主键方式一:
获得主键方式二:
批量增:
提示:批量增也能同时获取到主键,与上面的单个增的自动获取主键方式一样;这里就不再演示了。
数据访问层中的方法示例:
注:@InsertProvider需要指定(经过逻辑处理后)返回SQL语句的方法,以及该方法所在的类。
给出逻辑处理方法示例一(直接循环拼接sql语句):
注:使用#{}防止sql注入
注:在拼接的sql字符串中,用的直接是map中的key(即:上图Map中的key为listTest),而不是我们新new的集合对象(我们新new一个集合来获取map中对应key的集合的目的是:帮助我们知道集合的长度,进而进行逻辑判断)。
调用上图的方法,传过去的是这个:
注:由于我们的目的只是利用新new的集合来获取对应key的集合的长度,所以,即使我们不使用泛型,直接使用Map<String,Object>,(经测试)也是可以的。
给出逻辑处理方法示例二(采用MessageFormat拼接sql语句):
注:MessageFormat模板中的{0}即为第一个占位符。
注:使用#{}防止sql注入
注:和方式一一样,参数可以直接Map<String, Object>也行。
拼接sql字符串时,用的直接是map中的key(即:上图Map中的key为listTest),而不是我们新new的集合对象。
特别说明:
在数据访问层(即:Mapper层)调用SQL的代理方法时,我们也可以直接传递List过去,代理方法用Map接收,如:
Mapper层中的方法
处理SQL的方法
注:此时Mapper中的方法里的参数前,务必要有@Param,其值将被作为Map中的key;否者就要严格按照源码中的arg0之类的作为key了,最下面会讲到。
注:Provider中接收时,可以在接收参数时,就指定对应的泛型;也可以用Map<String, Object>接收后,再拆箱。
如果我们是将连库操作的数据放在Map<String ,Object>中项数据库表中插入的话,我们可以这么获取主键
Mapper层中的方法为:
注:这里以@Options为例的,使用@SelectKey获取主键也是一样的。
我们在调用dynamicInsertMultiParam这个方法时,在传过去的Map参数中,多放一个key,来接收新增后查询出来的id,如:
注意:key要和@Options注解中的keyProperty对应。
可以看见,获取到了新增后的id:
动态删@DeleteProvider
数据访问层中的方法示例:
注:@InsertProvider需要指定(经过逻辑处理后)返回SQL语句的方法,以及该方法所在的类。
给出逻辑处理方法示例:
注:此方法需要返回一个SQL字符串。
注:当需要传递多个参数时,处理方式与@InsertProvider一样。
动态改@DeleteUpdate
数据访问层中的方法示例:
注:@InsertProvider需要指定(经过逻辑处理后)返回SQL语句的方法,以及该方法所在的类。
给出逻辑处理方法示例:
注:此方法需要返回一个SQL字符串。
注:当需要传递多个参数时,处理方式与@InsertProvider一样。
动态查@SelectProvider(示例一)
数据访问层中的方法示例:
注:@InsertProvider需要指定(经过逻辑处理后)返回SQL语句的方法,以及该方法所在的类。
注:@InsertProvide与@Insert一样,如果column与property不一致,那么需要使用@Results指明对应关系。
给出逻辑处理方法示例:
注:因为参数没有放入一个实体类或Map中,所以这里#{}无法使用;因此建议:如果是使用了xxxProvider注解,那么参数都尽量放入实体类或Map中进行传参。
注:此方法需要返回一个SQL字符串。
注:当需要传递多个参数时,处理方式与@InsertProvider一样。
持有对象、集合:
声明:在分布式集群项目中,我们一般都会尽量避免显示的主外键关系、持有对象、持有集合等情况,目的是:降低耦合,方便程序的扩展以及后期维护等。
注:如果遇见了持有对象持有集合等情况,如果多次查询能够解决问题,那么就尽量避免一次性全部查询;如果非要一次查询解决持有对象持有集合的问题,那么需要引入xml文件,在xml文件中配置映射。
注:虽然@Result注解有@One、@Many注解,但是目前来说个人感觉并不那么好用。
动态查@SelectProvider(示例二)
数据访问层中的方法示例
Sql代理方法为
单元测试中的测试方法为
xml示例(持有对象):
说明:一个people持有一个身份证idcard对象
People实体类:
people表:
Idcard实体类:
idcard表:
xml文件位置:
数据访问层中的方法:
xml中的相关配置为:
注:更多关于xml中配置sql映射的内容,详见《程序员成长笔记(一)》第三部分,第四章,第四节。
Mapper接口中,调用方法时,参数是这么与sqlProvider中的形参匹配的(这是源码)
extractProviderMethodArguments方法是这样的:
所以,其实我们的mapper中的方法里,可以有多个形参,代理方法中也可以有多个形参如:
对应的代理方法为
注:由源码可知:时通过key来进行参数的匹配的。我们可以通过使用@Param来指定参数的key为多少,这样就能准确地匹配了。
注:参数前其实不使用@Param也是可以的。但是不建议这么做,因为如果我们不使用@Param来指定key的话,那么程序就会按照参数的顺序依次以arg0、arg1、arg2……来作为Map中的key;所以如果我们在mapper中对应的方的参数前不写key的话,那么在sqlProvider中的对应的方法的形参的顺序就要和传入时参数的顺序一致。而使用@Param的话,则没有此顾忌。
注:如果Mapper层中的方法传递多参数时,部分参数前使用了@Param()注解(或sqlProvider中对应方法的部分形参前使用了@Param()注解),那么其会顶替原来默认的key;以Mapper中的方法为例:
那么key依次为map1 和 arg1,即:map1取代了arg0作为key。对应sqlProvider中就要以相应的key取值。
注:更多细节上的使用,这里就不再一一说明了。感兴趣的话,可以去看下对应的源代码。