Mybatis3和Spring3整合下的编程式事务管理

Posted 咕噜大大

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis3和Spring3整合下的编程式事务管理相关的知识,希望对你有一定的参考价值。

咕噜大大,专注编程和单身30年!      

尊重原创,请大家转载时注明该文章来自:http://blog.csdn.net/ymh198816/article/details/43187747

大家都知道在对数据库操作时,最重要的就是要保证业务的原子性和一致性,这样才能基本保证数据库中数据的正确性。就比如说,某个系统中有两张表,一个是用户表users,另一个是用户的基本信息表users_info,用来保存用户真实姓名,地址,联系电话等,这两张表是1对1的关系,并且当新用户注册进users表中,相应地users_info表中也一定要生成对应的信息;这就需要两步操作,第一步是在users表中生成新用户的用户名,邮箱,密码等信息,第二步是在users_info表中生成新的记录并关联刚刚在users表中生成的用户记录;如果在第一步操作完成时服务器出现异常了,导致第二步中的用户基本信息的记录没有生成,那么日后去查询这个用户的基本信息时就会查询不到,程序报错。所以,这里就要用到事务管理的机制,将第一步和第二步一起看成是一个事务,如果在事务执行的过程中出现异常,那么就进行事务的回滚,数据返回到执行前的状态,只有当第一步和第二步都完成的时候,才提交事务,数据库中两张表的记录才会进行更新。


在mybatis中,我们使用SqlSession中的回滚,提交方法去编程式地管理事务;但是,当我们将Mybatis3和Spring3整合,使Mybatis中的Mappers或SqlSession能被Spring管理起来并注入到其它的bean中,却发现SqlSession的编程式事务管理方式无法正常运行并报UnsupportedOperationException的错误,这是因为使用了MyBatis-Spring插件后,总是由Spring来管理你的事务,所以Sqlsession被Spring管理了起来后,使得原先的SqlSession.rollback(),SqlSession.commit(),SqlSession.close()都失去了作用。同时在Spring事务之外用SqlSession的数据方法或调用Mapper方法提交的数据都会自动被commit。


所以当MyBatis3和Spring3整合后,我们无法再像以前一样用SqlSession来编程式地管理事务,取而代之的是使用实现了Spring3的统一事务接口PlatformTransactionManager的事务管理器DataSourceTransactionManager去编程式地处理事务。


让我们来举个栗子:

在用户表中注册新用户以及在用户信息表中创建该新用户所对应的基本信息记录,并将两条记录关联起来,同时用Spring的事务管理这整个过程。

首先在数据库中创建两张表:Users和User_Info, 以及这两张表所对应的JavaBean:

usersBean.java

public class usersBean 
	private int Users_Id;
	private String Users_Password;
	private String Users_Email;
	private int Users_Status;
	private String Users_Register_Time;
	private String Users_Nickname;

set and get method……

userInfoBean.java

public class userInfoBean 
	private int User_Info_Id;
	private String User_Info_Rname;
	private int User_Info_Gender;
	private String User_Info_Avatar;
	private String User_Info_Birthday;
	private int User_Info_Users_Id;
set and get method……

接着需要使用xml文件去mapper这两个javabean

users.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tutie.dao.loginDao">

	<resultMap type="com.tutie.domain.usersBean" id="usersmap">
		<id column="Users_Id" property="Users_Id"/>
		<result column="Users_Password" property="Users_Password"/>
		<result column="Users_Email" property="Users_Email"/>
		<result column="Users_Status" property="Users_Status"/>
		<result column="Users_Register_Time" property="Users_Register_Time"/>
		<result column="Users_Nickname" property="Users_Nickname"/>
	</resultMap>

<insert id="register" useGeneratedKeys="true"
    keyProperty="Users_Id"  parameterType="com.tutie.domain.usersBean">
    	insert into Users (Users_Password,Users_Email,Users_Status,Users_Register_Time,Users_Nickname)
        values (#Users_Password,#Users_Email,#Users_Status,#Users_Register_Time,#Users_Nickname)
</insert>
	
</mapper>
注意,这里的“KeyProperty”的值是对应的usersBean中主键的名称(事实上是对应javabean类中一个或多个属性名称),表示将插入用户记录时自动生成的主键值赋值给usersBean的主键。


userInfo.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tutie.dao.loginDao">

	<resultMap type="com.tutie.domain.userInfoBean" id="userinfomap">
		<id column="User_Info_Id" property="User_Info_Id"/>
		<result column="User_Info_Rname" property="User_Info_Rname"/>
		<result column="User_Info_Gender" property="User_Info_Gender"/>
		<result column="User_Info_Avatar" property="User_Info_Avatar"/>
		<result column="User_Info_Birthday" property="User_Info_Birthday"/>
		<result column="User_Info_Users_Id" property="User_Info_Users_Id"/>
	</resultMap>

<insert id="register_info" useGeneratedKeys="true"
    keyProperty="User_Info_Id"  parameterType="com.tutie.domain.userInfoBean">
    	insert into User_Info (User_Info_Rname,User_Info_Gender,User_Info_Avatar,User_Info_Birthday,User_Info_Users_Id)
        values (#User_Info_Rname,#User_Info_Gender,#User_Info_Avatar,#User_Info_Birthday,#User_Info_Users_Id)
</insert>
	
</mapper>

配置mapper接口

usersDao.java

public interface usersDao 
	
	public List<testUsersBean> getUsers();
		

配置spring的注入文件

applicationContext-beans.xml

先配置事务管理器,并保证这里的datasource和sqlSessionFactory的bean中的datasource一致关于sqlSessionFactory的bean如何配置可以去查看mybatis-spring整合的介绍手册,这里就不做说明了

	
	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>

接下来配置MapperFactoryBean,并将MapperFactoryBean中生成的mapper实例以及Spring的事务管理器DataSourceTransactionManager注入到业务bean中.

 	<bean id="loginDaoInjection"  class="org.mybatis.spring.mapper.MapperFactoryBean"
		scope="prototype">
		<property name="mapperInterface" value="com.tutie.dao.loginDao" />
		<property name="sqlSessionFactory" ref="sqlSessionFactory" />
	</bean>
 	<bean id="loginService" class="com.tutie.serviceImp.loginImp"
		scope="prototype">
		<property name="logindao" ref="loginDaoInjection" />
		<property name="ptm" ref="transactionManager" />
	</bean>

这里值得注意的地方是:当Mybatis和Spring整合后,我们不必写mapper接口的实现类,因为Spring自动帮你把SqlSession管理起来了,它会直接帮你生成mapper实例并注入到业务bean中,这也是为什么无法直接使用mybatis的SqlSession去管理事务的原因之一。在Spring的管理下,从某种意义上讲SqlSession对用户不可见。


下面在业务bean的实现类中使用Spring的事务管理器去管理注册新用户的行为:

loginImp.java

package com.tutie.serviceImp;

import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import com.tutie.dao.loginDao;
import com.tutie.domain.userInfoBean;
import com.tutie.domain.usersBean;
import com.tutie.service.loginInterface;

public class loginImp implements loginInterface 
	
	private loginDao logindao;
	private PlatformTransactionManager ptm;
	
	public void register(usersBean usersbean)
		
		DefaultTransactionDefinition def = new DefaultTransactionDefinition();
		def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
		TransactionStatus status = ptm.getTransaction(def);
		try
			logindao.register(usersbean);
			//create user base information
			userInfoBean userinfobean = new userInfoBean();
			userinfobean.setUser_Info_Users_Id(usersbean.getUsers_Id());
			logindao.register_info(userinfobean);
			
		 catch (Exception e) 
			ptm.rollback(status);
			e.printStackTrace();
			
		ptm.commit(status);
	

	public void setLogindao(loginDao logindao) 
		this.logindao = logindao;
	

	public void setPtm(PlatformTransactionManager ptm) 
		this.ptm = ptm;
	 
	
	

如果注册新用户logindao.register(usersbean)和注册新用户的基本信息logindao.register_info(userinfobean)这两个动作在执行过程中出现异常,那么就使用
rollback进行回滚,否则就commit提交这两个修改,这样就保证了每一个注册的新用户都能生成其对应的基本信息记录。

以上就是Mybatis和Spring整合下的编程式事务管理,欢迎大家对文章提出意见和指出错误的地方。

以上是关于Mybatis3和Spring3整合下的编程式事务管理的主要内容,如果未能解决你的问题,请参考以下文章

MyBatis 学习总结 05 Mybatis3.x与Spring3.x整合 OLD

mybatis3.0和spring3.0整合时出现异常

spring3.2+mybatis3.2+maven整合

Spring3 整合MyBatis3 配置多数据源 动态选择SqlSessionFactory(转)

Spring3.2+mybatis3.2+Struts2.3整合

Struts2+Spring3+MyBatis3整合以及Spring注解开发