Spring与Mybatis整合事务管理

Spring入门(二) AOP

Spring入门(二) 理解动态代理

Spring入门(一) IOC

Spring与Mybatis整合事务管理

本篇文章通过搭建一个Spring整合Mybatis的小项目,带你理解Spring与Mybatis整合的整个流程,重点还会介绍Spring的事务管理。这应该也是ssm框架整合最难理解的一步了,只要整合了sm后面再套个表现层就可以了。

maven项目添加依赖

首先使用maven创建一个java空项目,然后根据需要配置pom.xml文件来导入依赖的jar包。至于我为什么要选择maven项目来讲解,是因为要导入的jar包太多,我的mac电脑硬盘有限,如果每个小例子都要copy一份jar包,那我的硬盘也会所剩无几了。

先例举出项目需要依赖的jar包,既然是spring整合mybatis那自然是少不了mybatis的核心jar包和spring的核心jar包、ioc的jar包、aop的jar包、context的jar包,因为要用到事务管理,所以还需要添加spring-tx事务管理jar包和spring-jdbc包。此外,将mybatis整合到spring中还需要一个额外的mybatis-spring.jar包,要使用c3p0数据库连接池就需要c3p0.jar包,还有访问数据库不可缺失的数据库驱动工具包,这里使用mysql,所以是mysql-connector-java.jar包。

一些额外的需要:

junit:单元测试的jar包;

spring-test:spring提供的编写单元测试的框架;

aspectjweaver:AspectJ是一种编译期的用注解形式实现的aop,spring整合了AspectJ,在spring体系中可以使用aspectj语法来实现aop;

log4j:spring和mybatis打印日记依赖的工具包;

附pom.xml:

spring整合mybatis的配置

spring整合mybatis不需要在mybatis的核心配置文件中配置环境信息了,也不需要配置sql映射文件部分了,这些配置都交由spring来配置管理。

在resource目录下新建一个mybatis-config.xml文件,该文件作为mybatis的核心配置文件,只需要配置一些setting标签,比如配置日记打印来查看sql语句的输出。

[mybatis-config.xml]

创建数据库和表(tb_user),编写mybatis的dao接口(UserDao),编写sql映射文件(UserMapper.xml)。

[创建库和表]

[UserDao.java]注:该接口不需要写实现类

在resource目录下新建一个mapper目录,用于存储sql的xml映射文件。

[UserMapper.xml]

在resource目录下新建一个db.properties文件。

[db.properties]

创建applicationContext.xml文件,这是spring的配置文件。

导入前面创建的db.properties文件中的键值对

在spring的配置文件中配置数据源,这里使用c3p0.jar包提供的ComboPooledDataSource类,即使用c3p0连接池配置数据源。

这里有必要介绍一个知识点,即FactoryBean,让你看后文能知其所以然。

Spring中有两种类型的Bean,一种是普通Bean,其返回的对象是指定类的一个实例,另一种是实现FactoryBean接口的Bean,实现FactoryBean接口的Bean跟普通Bean不同,其返回的对象是该实现FactoryBean接口的实例的getObject方法所返回的对象。

FactoryBean通常是用来创建比较复杂的Bean,一般的Bean直接用xml配置即可,但如果一个Bean的创建过程中涉及到很多其他的bean和复杂的逻辑,这时需要用FactoryBean。

[FactoryBean源码]

配置SqlSessionFactory,使用mybatis-spring.jar包提供的SqlSessionFactoryBean类,该类实现了spring的FactoryBean接口。这个配置可以简单理解为:配置了一个类型为SqlSessionFactoryBean的bean,id为sqlSessionFactory,因为SqlSessionFactoryBean是实现FactoryBean接口的,所以取id为sqlSessionFactory的bean的时候[比如getBean("sqlSessionFactory")],取得的不是这个SqlSessionFactoryBean实例,而是其getObject()方法返回的实例。

SqlSessionFactoryBean实现FactoryBean接口的三个接口源码。

配置实现指定mapper接口的bean(动态代理实现,这里不关注具体的实现原理,我们只要能拿到一个实现该mapper接口的实例就行了)。这个配置可以简单理解为:配置了一个类型为MapperFactoryBean的bean,id为userDao,因为MapperFactoryBean是实现FactoryBean接口的,所以取id为userDao的bean的时候[比如getBean("userDao")],取得的不是这个MapperFactoryBean实例,而是其getObject()方法返回的实例。

MapperFactoryBean实现FactoryBean接口的三个接口源码。

上面方法不推荐使用了,因为 mapper接口多的时候配置太麻烦,也使配置文件臃肿,下面介绍使用自动扫描mapper接口的方式,这样不需要一个个的为mapper接口配置bean。当我们需要使用这些bean时,因为每个mapper接口的实现类只有一个,bean也是单例的,所以在使用@Autowired这样声明注入时不需要指定bean的名称,spring会找到该接口类型的实现类的bean来注入,而如果想指定bean的名称可以使用bean接口的类名(首字母小写)。

定义业务层接口,编写业务层接口的实现类。

[UserService接口]

[UserService实现类]

修改applicationContext.xml配置文件,开启ioc注解功能。

编写测试类,验证整合完成

回忆MyBatis的单独使用

是不是见不到SqlSession的影子了,前面我写的那篇Mybatis入门介绍mybatis单独使用,记得是如何访问数据库的吗?

建议编写log4j的日记配置文件,可以查看sql语句及一些日记信息的输出。在resource目录下新建log4j.properties配置文件,这里我只是配置了控制台的打印输出,详细配置就不重复介绍了,之前写的文章都讲过。

[log4j.properties]

使用spring的aop功能

将上一篇将aop的文章中的例子拿来用,就是一个日记打印的例子。编写一个切面类LogAspect,使用注解@Component将其声明为一个bean,再使用注解@Aspect将其声明为一个切面。

[LogAspect.java]

修改applicationContext.xml配置,在bean自动扫描配置添加该切面类所在包。

然后开启aop注解功能

运行测试代码,查看通知是否切入成功。

配置spring对数据库的事务管理

修改applicationContext.xml配置文件,开启事务注解功能并配置数据库的事务管理者。使用spring-jdbc.jar包提供的DataSourceTransactionManager类配置数据库事务管理者。

这里只介绍声明式事务管理,使用@Transactional注解。

[@Transactional]

将UserService的实现类修改为如下。

在userRegist方法中要做的事情就是将user信息保存到数据库,而我在该方法中模拟抛出了一个异常,当抛出异常时如果不指定noRollbackFor就会执行事务回滚。

将roes/=0;这句注释掉,运行测试方法可以看到控制台输出如下信息:(测试方法还是上面测试整合是否成功的那个代码)

1

isolation事务隔离级别

isolation配置事务的隔离级别,Isolation枚举类型:

DEFAULT:默认值,使用底层数据库的默认隔离级别。对大部分数据库而言就是READ_COMMITTED。

READ_UNCOMMITTED:一个事务可以读取另一个事务修改但还没有提交的数据。(不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别)

READ_COMMITTED:一个事务只能读取另一个事务已经提交的数据。(可以防止脏读,这也是大多数情况下的推荐值)

REPEATABLE_READ:一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。(可以防止脏读和不可重复读)

SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰。(可以防止脏读、不可重复读以及幻读)(严重影响程序的性能)

2

propagation事务传播

如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。propagation配置事务传播行为,Propagation枚举类型:

REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。

SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。

MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。

REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。

NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。

NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。

NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于REQUIRED。

3

readOnly只读事务

readOnly配置事务只读属性,只读事务用于客户代码只读但不修改数据的情形。

4

timeout事务超时

timeout配置事务超时,单位是秒,指定一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。

5

配置回滚规则

附完整的applicationContext.xml:

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180826G01O5P00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券