Java注解实现增删改查CRUD

以前,我们都把对数据库的增删改查语句写在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<Map<String, Object>>这样的来接收多行数据。一个Map<String, Object>只存储一行数据。

法二:

   每一行数据专门拿一个对象模型来接收,并指定以该模型的哪一个属性作为key。

注:法一是List的每一个Map中只有一条数据;法二是多条数据都放在同一个Map中,以不同的key来对应不同的行。

注:法二依赖于对象模型,且法二在选择以对象的什么属性作为key时,要考虑是否会重复(如果作为key的属性的属性
     值可能会重复,那么在Map里可能发生数据覆盖的情况)。

简单查(以 集合类型 接收数据)示例:

示例一:

示例二:

注:如果查询结果横跨多个实体模型,那么我们使用List来接收数据。

动态语句:

我们都知道如何在xml中处理动态的SQL语句,那么使用Java注解如何处理呢?需要使用@xxxProvider,并指定(经过逻辑处理后)返回SQL语句的方法,以及该方法所在的类

注:使用@xxxProvider时,就不要使用@Param了,否者容易出错。

注:xxx为InsertUpdateDeleteSelect

注:这些(代理)方法最好不要重载,避免不必要的问题。

注:我们可以单独创建一个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取值。

注:更多细节上的使用,这里就不再一一说明了。感兴趣的话,可以去看下对应的源代码。

微笑demo项目托管在https://github.com/JustryDeng/PublicRepository

使用Junit对所写方法进行的测试

微笑如有不当之处,欢迎指正

微笑本文已经被收录进《程序员成长笔记(二)》,作者JustryDeng

猜你喜欢

转载自blog.csdn.net/justry_deng/article/details/80707982
今日推荐