前言
简单的记录使用spring事物的一些问题
正文
jdbcTemplate与hibernateTemplate事物的管理
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
在自己的项目中配置了上面的事务管理,在想,如果是jdbcTemplate,这个HibernateTransactionManager还适用吗?查了一下资料,如jdbcTemplate与hibernateTemplate事务共享配置
《Hibernate与JdbcTemplate共享事务管理》
《Hibernate 与spring jdbcTemplate共享事物的管理》
《HibernateTransactionManager事务管理》
从上面文章自己做了以下的配置以及代码测试
<?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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
">
<context:property-placeholder location="classpath:config/mysql.properties"/>
<context:component-scan base-package="org.test" />
<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="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<!-- 依赖注入数据源,注入正是上面定义的dataSource -->
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan">
<list>
<value>myblog.pojo</value>
<!--<value>com.myzone.exam.pojo.OptionsPO</value>
<value>com.myzone.exam.pojo.SubjectsPO</value>
<value>com.myzone.exam.pojo.SubjectTypePO</value>
--></list>
</property>
<!-- 定义Hibernate的SessionFactory的属性 -->
<property name="hibernateProperties">
<props>
<!-- 指定数据库方言 -->
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLInnoDBDialect</prop>
<!-- 是否根据需要每次自动创建数据库 -->
<prop key="hibernate.hbm2ddl.auto">update</prop>
<!-- 显示Hibernate持久化操作所生成的SQL -->
<prop key="hibernate.show_sql">true</prop>
<!-- 将SQL脚本进行格式化后再输出 -->
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate4.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<!-- 定义事务管理器(声明式的事务) -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="interceptorPointCuts"
expression="execution(* org.test.service.*.*(..))" />
<aop:advisor advice-ref="txAdvice"
pointcut-ref="interceptorPointCuts" />
</aop:config>
</beans>
上面事物管理使用框架提供的org.springframework.orm.hibernate4.HibernateTransactionManager
在里面就配置了一个sessionFactory(可以成功因为共用一个数据源?)
代码-service层
public void register(RegisterDTO dto) {
//是否存在用户
if(userDao.findUser(dto) != null) {
throw new RuntimeException("已经存在用户");
}
//注册用户,使用jdbcTempalte插入用户信息
int userid = userDao.addUser(dto);
//使用hibernate插入用户信息
System.out.println("hiberante输出:" + userDao.addUserByHibernate(dto));
//注册登录信息
dto.setUserid(userid);
logonDao.addLogon(dto);
//抛出异常回滚
throw new RuntimeException();
}
代码-userDao
@Override
public int addUser(final RegisterDTO dto) {
String sql = "insert into user1(displayname) values(?);";
KeyHolder key = new GeneratedKeyHolder();
int result = jdbcTemplate.update(new PreparedStatementCreator(){
@Override
public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
PreparedStatement ps = connection.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
ps.setString(1, dto.getDisplayname());
return ps;
}
}, key);
if(result == 0) {
throw new RuntimeException("对数据库没有影响,因为操作的结果返回为0");
}
return key.getKey().intValue();
}
public int addUserByHibernate(RegisterDTO dto) {
final String sql = "insert into user1(displayname) values(:displayname);";
final String displayname = dto.getDisplayname();
return hiberanteTemplate.executeWithNativeSession(new HibernateCallback<Integer>() {
@Override
public Integer doInHibernate(Session session) throws HibernateException {
Query query = session.createSQLQuery(sql);
query.setParameter("displayname", displayname);
return query.executeUpdate();
}
});
}
备注:第二个方法使用hibernateTemplate的Query来插入用户信息,不需要配置hibernate与数据库的映射关系(这里使用注解),如果是hibernate.save(Entity)保存实体类的话,需要配置orm的关系(这里不再配置文件配置,而是注解)
代码-单元测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:config/spring-config.xml")
public class RegisterServiceTest {
@Resource(name="registerService")
private IRegisterService service;
@Test
public void registerTest() {
RegisterDTO dto = new RegisterDTO();
dto.setDisplayname("superman123");
dto.setPassword("99999");
service.register(dto);
}
}
备注:单元测试如上,可以获取IOC容器中的对象实现注入,service层、dao层使用@Component (@controller 控制器(注入服务) 2、@service 服务(注入dao) 3、@repository dao(实现dao访问))实现bean定义,在单元测试也能从IOC容器中获取。效果反正和启动服务器访问差不多,上面我少配置了@Transactional,这个注解,在单元测试完,自动回滚,所以我取消掉了
经过测试,上面操作可以在抛出异常的时候对jdbcTemplate方法和hibernateTemplate方法进行回滚
问题
对注解@Transactional这里有点迷糊