Spring整合hibernate -声明事务管理
目录
1 sessionFactory 注入HibernateTransactionManager
2 XML配置的配置
3 添加annotation-driven
4 引入JAR包
5在service层添加事务声明的注释
6 改写数据库的实现类的方法,不再需要开始事务和提交事务,并且使用getCurrentSession
7 编写测试类通过
通过Spring的事务管理可以实现,对事务的统一管理,并且写节省冗余代码,结构清晰 抓到runtimeException进行回滚,
事务的策略Springl默认是required
1 sessionFactory注入org.springframework.orm.hibernate4.HibernateTransactionManager
<bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="mySessionFactory"></property> </bean>
2 引入XML配置
1 xmlns:tx="http://www.springframework.org/schema/tx"
2 http://www.springframework.org/schema/tx
3 http://www.springframework.org/schema/tx/spring-tx.xsd
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd ">
3 添加annotation-driven
<tx:annotation-driven transaction-manager="txManager" />
4 引入JAR包
aopalliance-1.0
5在service层添加事务声明的注释
@Transactional public void add(User user) { userDao.save(user); }
6 改写数据库的实现类的方法,不再需要开始事务和提交事务,并且使用getCurrentSession
public void save(User user) { System.out.println(user.getName()+"-->"+user.getRemark()+" save --调用UserDaoImpl2!"); Session s = mySessionFactory.getCurrentSession(); s.save(user); }
7 测试一下
@Test public void testAdd() { ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("beans.xml"); UserServiceImpl UserServiceImpl = (UserServiceImpl)app.getBean("userServiceImpl"); UserServiceImpl.add(user);//调用方法 }
8 测试通过
下面会详细给出代码
9编译常见的报错信息
1 Add CGLIB to the class path or specify proxy interfaces.
引入 cglib-nodep-2.1_3.jar
2 org.hibernate.HibernateException: save is not valid without active transaction
去掉sessionFactory的property的配置 hibernate.current_session_context_class=thread
3 org.hibernate.MappingException: Unknown entity: com.entity.Log
sessionFactory里需要配置property的实体类
<property name="annotatedClasses"> <list> <value>com.entity.User</value> <value>com.entity.Log</value> </list> </property>
--------------------------------------------------------------------------------------------
Spring的事务管理具体的应用
例如 有一个服务service是完成以下功能
1 保存一个用户信息进A表,保存成功后打印一条日志进入B表
2 如果日志打印报错则插入的A表的用户回滚
完整的代码
XML
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd "> <context:component-scan base-package="com.*"></context:component-scan> <tx:annotation-driven transaction-manager="txManager" /> <bean id="mappings" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <value>classpath:jdbc.properties</value> </property> </bean> <!-- <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">--> <!-- <property name="driverClassName" value="com.mysql.jdbc.Driver"/>--> <!-- <property name="url" value="jdbc:mysql://localhost:3306/spring"/>--> <!-- <property name="username" value="root"/>--> <!-- <property name="password" value="root"/>--> <!-- </bean>--> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <bean id="mySessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="annotatedClasses"> <list> <value>com.entity.User</value> <value>com.entity.Log</value> </list> </property> <property name="hibernateProperties"> <value> hibernate.dialect=org.hibernate.dialect.MySQLDialect hibernate.show_sql=true <!-- hibernate.current_session_context_class=thread--> </value> </property> </bean> <bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="mySessionFactory"></property> </bean> </beans>
service
package com.serviceImpl; import javax.annotation.Resource; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import com.dao.LogDao; import com.dao.UserDao; import com.entity.Log; import com.entity.User; @Component public class UserServiceImpl { private UserDao userDao; private LogDao logDao; @Transactional public void add(User user) { userDao.save(user); Log log = new Log(); log.setContent(user.getName()); logDao.save(log); } public void update(User user) { userDao.update(user); } public void init() {// 初始方法 System.out.println("init"); } public void destroy() {// 销毁方法 System.out.println("destory"); } public UserDao getUserDao() { return userDao; } @Resource(name="userDaoImpl2") public void setUserDao(UserDao userDao) { this.userDao = userDao; } public LogDao getLogDao() { return logDao; } @Resource public void setLogDao(LogDao logDao) { this.logDao = logDao; } }
UserDaoImpl2
package com.daoImpl; import javax.annotation.Resource; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import com.dao.UserDao; import com.entity.User; @Component public class UserDaoImpl2 implements UserDao{ SessionFactory mySessionFactory; public void save(User user) { System.out.println(user.getName()+"-->"+user.getRemark()+" save --调用UserDaoImpl2!"); Session s = mySessionFactory.getCurrentSession(); s.save(user); } public void update(User user) { System.out.println(user.getName()+"-->"+user.getRemark()+" update --调用UserDaoImpl2!"); Session s = mySessionFactory.getCurrentSession(); s.update(user); } public SessionFactory getMySessionFactory() { return mySessionFactory; } @Resource public void setMySessionFactory(SessionFactory mySessionFactory) { this.mySessionFactory = mySessionFactory; } }
logImpl
package com.daoImpl; import javax.annotation.Resource; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.springframework.stereotype.Component; import com.dao.LogDao; import com.entity.Log; @Component public class LogDaoImpl implements LogDao{ SessionFactory mySessionFactory; public void save(Log log) { Session s = mySessionFactory.getCurrentSession(); s.save(log); } public SessionFactory getMySessionFactory() { return mySessionFactory; } @Resource public void setMySessionFactory(SessionFactory mySessionFactory) { this.mySessionFactory = mySessionFactory; } }
logDao,userDao
package com.dao; import com.entity.Log; import com.entity.User; public interface LogDao { public void save(Log log); }
package com.dao; import com.entity.User; public interface UserDao { public void save(User user); public void update(User user); }
实体类
package com.entity; import javax.persistence.Entity; import javax.persistence.Id; @Entity public class User { @Id private int id; private String name; private String remark; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getRemark() { return remark; } public void setRemark(String remark) { this.remark = remark; } public int getId() { return id; } public void setId(int id) { this.id = id; } }
package com.entity; import javax.persistence.Entity; import javax.persistence.Id; @Entity public class Log { @Id private int id; private String content; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } }
最后是测试类
package com.serviceImpl.test; import org.junit.Before; import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.entity.User; import com.serviceImpl.UserServiceImpl; public class UserServiceImplTest { User user; @Before public void setUp() throws Exception { user = new User(); user.setName("ttN"); user.setRemark("ttR"); } @Test public void testAdd() { ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("beans.xml"); UserServiceImpl UserServiceImpl = (UserServiceImpl)app.getBean("userServiceImpl"); UserServiceImpl.add(user);//调用方法 } }
执行结果
ttN-->ttR save --调用UserDaoImpl2!
Hibernate: insert into User (name, remark, id) values (?, ?, ?)
Hibernate: insert into Log (content, id) values (?, ?)
接下来测试一下,如果写入日志失败是否能够回滚
模拟 模拟日志的ID重复了,导致失败
@Transactional public void add(User user) { userDao.save(user); Log log = new Log(); log.setId(1); logDao.save(log); }
测试类
@Before public void setUp() throws Exception { user = new User(); user.setName("testRollBack"); user.setRemark("testRollBack"); } @Test public void testAdd() { ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("beans.xml"); UserServiceImpl UserServiceImpl = (UserServiceImpl)app.getBean("userServiceImpl"); UserServiceImpl.add(user);//调用方法 }
执行结果
testRollBack-->testRollBack save --调用UserDaoImpl2!
Hibernate: insert into User (name, remark, id) values (?, ?, ?)
Hibernate: insert into Log (content, id) values (?, ?)
报错信息
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null];
Caused by: java.sql.SQLException: Column 'content' cannot be null
存入的USER数据已经回滚
实体类其实还可以通过自动扫描的方式获取
<!-- <property name="annotatedClasses">--> <property name="packagesToScan"> <list> <value>com.entity</value> <!-- 这些都不需要一个一个写了 <value>com.entity.User</value>--> <!-- <value>com.entity.Log</value>--> </list> </property>