以前,我们都把对数据库的增删改查语句写在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。
一级颜色:绿色 二级颜色:黄色 注意事项:红色 插入说明:蓝
先给出MySQL数据库中的相关employee表
数据访问层中的查询语句示例:
注:如果参数只有一个,那么可以直接#{属性名}进行属性值获取,如果有多个参数,必须使用@Param指明。
注:如果只有一个参数的话,那么可以不使用@Param,此时#{xxx}和keyProperty = “xxx”中的xxx可以直接写实体类模型的属性名。
注:如果有多个参数,那么我们需要使用@Param来进行指明,当然也推荐一个参数时也使用@Param注解。如果使用@Param指明参数了,且在注解中使用到了该参数的某些值时,一定要指明是该参数的。
如:这里的keyProperty = “e.id”是可以的;而keyProperty = “id”不可以。
注:方式二的注意事项与方式一一样。
注:使用注解CRUD时,可以多个参数,这些参数可以是普通参数,也可以是复杂参数。
注:使用自动获取主键@Options或@SelectKey能正常获取到该对象插入数据库表中后的主键。
先给出MySQL数据库中的相关employee表
先给出MySQL数据库中的相关employee表
先给出MySQL数据库中的相关employee表
数据访问层中的查询语句示例一:
数据访问层中的查询语句示例二:
数据访问层中的查询语句示例:
注:如果没有任何数据,那么返回的Employy对象为null。
注:id = true出现在哪里,就说明那个参数是主键。
如:
就说明idCard是主键。
注:如果接收查询结果的,是一个对象模型,那么程序是通过对应的有参构造或则无参构造+setter方法,将结果放进实体类模 型的。
即:这就要求我们,在创建实体类模型时,一定要创建有对应的有参构造或无参构造+setter方法。
注:如果column名字与property不一致,那么需要在Result中指出来。
注:如果以Map
数据的;我们知道HashMap是无序的,比如SELECT e.id,e.e_name,e.e_gender,e.e_age …… 时,
将map结果进行toString的话,就会观察到输出的字段的顺序不一定是id、e_name、e_gender、e_age;
此时,如果我们想使map中的数据顺序是SQL语句指定的字段顺序的话,那么可以使用LinkedHashMap
来接收查询出来的数据。
注:上图中的此写法只能接收一条(一行)数据内容。如果想接收多条(多行)数据内容,那么可以:
法一:以形如List
法二:
每一行数据专门拿一个对象模型来接收,并指定以该模型的哪一个属性作为key。
注:法一是List的每一个Map中只有一条数据;法二是多条数据都放在同一个Map中,以不同的key来对应不同的行。
注:法二依赖于对象模型,且法二在选择以对象的什么属性作为key时,要考虑是否会重复(如果作为key的属性的属性
值可能会重复,那么在Map里可能发生数据覆盖的情况)。
示例一:
示例二:
注:如果查询结果横跨多个实体模型,那么我们使用List来接收数据。
动态语句:
我们都知道如何在xml中处理动态的SQL语句,那么使用Java注解如何处理呢?需要使用@xxxProvider,并指定(经过逻辑处理后)返回SQL语句的方法,以及该方法所在的类。
注:使用@xxxProvider时,就不要使用@Param了,否者容易出错。
注:xxx为Insert、Update、Delete、Select。
注:这些(代理)方法最好不要重载,避免不必要的问题。
注:我们可以单独创建一个package、创建一个类来放置这些方法,如:
数据访问层中的方法示例:
注:@InsertProvider需要指定(经过逻辑处理后)返回SQL语句的方法,以及该方法所在的类。
给出逻辑处理方法示例:
数据访问层中的方法示例:
注:@InsertProvider需要指定(经过逻辑处理后)返回SQL语句的方法,以及该方法所在的类。
给出逻辑处理方法示例:
注:如果数据访问层中的对应的方法有多个参数时,那么此方法的参数类型必须为Map
注:此方法需要返回一个SQL字符串。
获得主键方式一:
获得主键方式二:
提示:批量增也能同时获取到主键,与上面的单个增的自动获取主键方式一样;这里就不再演示了。
数据访问层中的方法示例:
注:@InsertProvider需要指定(经过逻辑处理后)返回SQL语句的方法,以及该方法所在的类。
给出逻辑处理方法示例一(直接循环拼接sql语句):
注:使用#{}防止sql注入
注:在拼接的sql字符串中,用的直接是map中的key(即:上图Map中的key为listTest),而不是我们新new的集合对象(我们新new一个集合来获取map中对应key的集合的目的是:帮助我们知道集合的长度,进而进行逻辑判断)。
调用上图的方法,传过去的是这个:
注:由于我们的目的只是利用新new的集合来获取对应key的集合的长度,所以,即使我们不使用泛型,直接使用Map
给出逻辑处理方法示例二(采用MessageFormat拼接sql语句):
注:MessageFormat模板中的{0}即为第一个占位符。
注:使用#{}防止sql注入
注:和方式一一样,参数可以直接Map
拼接sql字符串时,用的直接是map中的key(即:上图Map中的key为listTest),而不是我们新new的集合对象。
特别说明:
在数据访问层(即:Mapper层)调用SQL的代理方法时,我们也可以直接传递List过去,代理方法用Map接收,如:
Mapper层中的方法
处理SQL的方法
注:此时Mapper中的方法里的参数前,务必要有@Param,其值将被作为Map中的key;否者就要严格按照源码中的arg0之类的作为key了,最下面会讲到。
注:Provider中接收时,可以在接收参数时,就指定对应的泛型;也可以用Map
Mapper层中的方法为:
注:这里以@Options为例的,使用@SelectKey获取主键也是一样的。
我们在调用dynamicInsertMultiParam这个方法时,在传过去的Map参数中,多放一个key,来接收新增后查询出来的id,如:
注意:key要和@Options注解中的keyProperty对应。
可以看见,获取到了新增后的id:
数据访问层中的方法示例:
注:@InsertProvider需要指定(经过逻辑处理后)返回SQL语句的方法,以及该方法所在的类。
给出逻辑处理方法示例:
注:此方法需要返回一个SQL字符串。
注:当需要传递多个参数时,处理方式与@InsertProvider一样。
数据访问层中的方法示例:
注:@InsertProvider需要指定(经过逻辑处理后)返回SQL语句的方法,以及该方法所在的类。
给出逻辑处理方法示例:
注:此方法需要返回一个SQL字符串。
注:当需要传递多个参数时,处理方式与@InsertProvider一样。
数据访问层中的方法示例:
注:@InsertProvider需要指定(经过逻辑处理后)返回SQL语句的方法,以及该方法所在的类。
注:@InsertProvide与@Insert一样,如果column与property不一致,那么需要使用@Results指明对应关系。
给出逻辑处理方法示例:
注:因为参数没有放入一个实体类或Map中,所以这里#{}无法使用;因此建议:如果是使用了xxxProvider注解,那么参数都尽量放入实体类或Map中进行传参。
注:此方法需要返回一个SQL字符串。
注:当需要传递多个参数时,处理方式与@InsertProvider一样。
持有对象、集合:
声明:在分布式集群项目中,我们一般都会尽量避免显示的主外键关系、持有对象、持有集合等情况,目的是:降低耦合,方便程序的扩展以及后期维护等。
注:如果遇见了持有对象持有集合等情况,如果多次查询能够解决问题,那么就尽量避免一次性全部查询;如果非要一次查询解决持有对象持有集合的问题,那么需要引入xml文件,在xml文件中配置映射。
注:虽然@Result注解有@One、@Many注解,但是目前来说个人感觉并不那么好用。
数据访问层中的方法示例
Sql代理方法为
单元测试中的测试方法为
说明:一个people持有一个身份证idcard对象
People实体类:
people表:
Idcard实体类:
idcard表:
xml文件位置:
数据访问层中的方法:
xml中的相关配置为:
注:更多关于xml中配置sql映射的内容,详见《程序员成长笔记(一)》第三部分,第四章,第四节。
mapper层中方法是这样的:
注:此方式和xml的方式几乎一致。
注:此方式只不过是将一些逻辑交给ibatis来处理了;当然我们也可以自己处理,如使用@SelectProvider等
注解来处理这些逻辑。
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取值。
注:更多细节上的使用,这里就不再一一说明了。感兴趣的话,可以去看下对应的源代码。