Code Bye

Spring 3 + Hibernate4 事务不成功

先贴配置吧:

<?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-3.0.xsd  
           http://www.springframework.org/schema/context  
           http://www.springframework.org/schema/context/spring-context-3.0.xsd  
           http://www.springframework.org/schema/aop  
           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
           http://www.springframework.org/schema/tx  
           http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
    
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="com.mysql.jdbc.Driver" />
		<property name="username" value="root" />
		<property name="password" value="123" />
		<property name="url" value="jdbc:mysql://localhost:3306/FindClass" />
	</bean>

	<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" >
		<property name="dataSource" >
			<ref local="dataSource"/>
		</property>
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
				<!-- 
				<prop key="javax.persistence.validation.mode">none</prop>
				 -->
				<prop key="hibernate.show_sql">true</prop>
				<prop key="hibernate.format_sql">true</prop>
				<prop key="hibernate.current_session_context_class">org.springframework.orm.hibernate4.SpringSessionContext</prop>
				<prop key="hibernate.connection.autocommit">false</prop>
			</props>
		</property>
		<property name="packagesToScan">
			<list>
				<value>funs.el.mvc.model</value>
			</list>
		</property>
	</bean>


	<!-- 事务管理器 -->
	 
	<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
		<property name="sessionFactory">
			<ref local="sessionFactory"/>
		</property>
	</bean>

	<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />

	<tx:advice id="txAdvice" transaction-manager="transactionManager">
	<tx:attributes>
		<tx:method name="get*" propagation="REQUIRED" read-only="true" />
		<tx:method name="find*" propagation="REQUIRED" read-only="true" />
		<tx:method name="list*" propagation="REQUIRED" read-only="true" />
		<tx:method name="load*" propagation="REQUIRED" read-only="true" />
		<tx:method name="save*" propagation="REQUIRED" rollback-for="Exception" />
		<tx:method name="add*" propagation="REQUIRED" rollback-for="Exception" />
		<tx:method name="save" propagation="REQUIRED" rollback-for="Exception" />
		<tx:method name="update*" propagation="REQUIRED"
			rollback-for="Exception" />
			<tx:method name="update" propagation="REQUIRED"
			rollback-for="Exception" />
		<tx:method name="delete*" propagation="REQUIRED"
			rollback-for="Exception" />
			<tx:method name="delete" propagation="REQUIRED"
			rollback-for="Exception" />
		<tx:method name="*" propagation="REQUIRED" />
	</tx:attributes>
	</tx:advice>
	<aop:aspectj-autoproxy />
	<aop:config>
		<aop:pointcut id="aopPointcut"
			expression="execution(* funs.el.mvc.service..*.*ServiceImpl.*(..))" />
		<aop:advisor advice-ref="txAdvice" pointcut-ref="aopPointcut"/>
	</aop:config>
	 

</beans>

我再整合spring3+Hibernate4,里面的ORM和spring的 bean都是用注解的方式配置的,事务我也想用注解的方式配置,但怎么配置也配置不对,上面就是我配置事务的代码(貌似直接加个@Transactional注解就可以直接写上面的tx:annotation-driven就可以了吧?)。但事实上不行。
其一,我目的是当整个service方法抛出异常了,事务代理自动帮我回滚,但我测试过不行。
其二,我将所有注释的和配置形式的事务代理配置都删掉了,结果我随便一个带修改的操作也成功将数据库修改了(按道理我没配置开启事务的话,是不是不应该自动提交的呢?)。
我已经在配置里显示的写了:<prop key=”hibernate.connection.autocommit”>false</prop>
貌似hibernate默认就是不开启自动提交的。

另外我附上一段DAO的插入代码:

@Override
	public boolean add(T t) {
		// TODO Auto-generated method stub
		sessionFactory.getCurrentSession().save(t);
		return true;
	}
看下楼主@Transactional注解加在哪了?
可以到我的博客看下我写的那个开源项目,里面有spring的事务,可以参考下
http://blog.csdn.net/shadowsick
建议在配置事物管理的时候,不要使用注解的方式,为什么可以百度一下原因。hibernate自身不是自动提交的,需要自己手动开启事物 持久操作 然后 commit,当hibernate由spring管理之后,就是自动的了,不要手动开启 提交
楼主
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />

这个代码是启用注解开启事务。
而下面的tx:advice、tx:attributes等是基于xml来启用事务。

建议楼主先把先后分开来试试。即要么用注解配置,要么用xml来配置。但推荐用xml配置。

看看这里类似的问题回答得合不合适
http://www.iteye.com/problems/481
引用 4 楼 NNTT2010 的回复:

楼主

<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />

这个代码是启用注解开启事务。
而下面的tx:advice、tx:attributes等是基于xml来启用事务。

建议楼主先把先后分开来试试。即要么用注解配置,要么用xml来配置。但推荐用xml配置。

这个我试过了,我通过分别注释去尝试,都不行,比如我直接将事务注释和<tx:annotation这句都去掉,保留声明配置,但事务依旧还是那样,就是几十你再get方法里面增加一个dao.add操作,它也可以插进数据库中,就好想本身就是自带自动提交事务一样!

引用 5 楼 dracularking 的回复:

看看这里类似的问题回答得合不合适
http://www.iteye.com/problems/481

貌似不可以,我也是已经将
<prop key=”hibernate.connection.autocommit”>false</prop>了
而且,我的MYSQL当初安装的时候也有设置InnDB的

引用 3 楼 qiangan7788 的回复:

建议在配置事物管理的时候,不要使用注解的方式,为什么可以百度一下原因。hibernate自身不是自动提交的,需要自己手动开启事物 持久操作 然后 commit,当hibernate由spring管理之后,就是自动的了,不要手动开启 提交

我尝试把注释事务去掉,保留那个配置形式的事务,但还是不行!我的ORM,SPRING BEAN都是注释配置的

引用 8 楼 tangtangzizi 的回复:
Quote: 引用 3 楼 qiangan7788 的回复:

建议在配置事物管理的时候,不要使用注解的方式,为什么可以百度一下原因。hibernate自身不是自动提交的,需要自己手动开启事物 持久操作 然后 commit,当hibernate由spring管理之后,就是自动的了,不要手动开启 提交

我尝试把注释事务去掉,保留那个配置形式的事务,但还是不行!我的ORM,SPRING BEAN都是注释配置的

百度回答你吗的把我回复给隐藏了。。
把你配置文件中这段删除  hibernate.current_session_context_class=org.springframework.orm.hibernate4.SpringSessionContext

引用 8 楼 tangtangzizi 的回复:
Quote: 引用 3 楼 qiangan7788 的回复:

建议在配置事物管理的时候,不要使用注解的方式,为什么可以百度一下原因。hibernate自身不是自动提交的,需要自己手动开启事物 持久操作 然后 commit,当hibernate由spring管理之后,就是自动的了,不要手动开启 提交

我尝试把注释事务去掉,保留那个配置形式的事务,但还是不行!我的ORM,SPRING BEAN都是注释配置的

我是用你的配置写了个简单的例子。没有问题。
你是用的是什么架构?只是 spring +hibernate吗?没有使用其他的例如spring mvc 之类的吗?

引用 1 楼 yx444535180 的回复:

看下楼主@Transactional注解加在哪了?

引用 1 楼 yx444535180 的回复:

看下楼主@Transactional注解加在哪了?

加载一个service里面:

@Transactional
@Service("roomService")
public class RoomServiceImpl extends BaseService<IRoomDAO> implements RoomService{

请求大致的结构是:
Action(action调用service的某个方法【测试过甚至名字叫get开头的方法依然可以插入到数据库中】) -> service(@Transactional在这里) -> dao(service调用dao的add方法)

Service的大致结构是:
BaseService(里面有一个泛型的dao,以后通过继承BaseService改掉这个泛型的dao)  implements IBaseService(BaseService的接口,也是基本接口)
   public class RoomServiceImpl extends BaseService<IRoomDAO> implements RoomService (以后这个service所需要的方法在这里新增,不污染基础的接口)

引用 10 楼 archy123 的回复:
Quote: 引用 8 楼 tangtangzizi 的回复:
Quote: 引用 3 楼 qiangan7788 的回复:

建议在配置事物管理的时候,不要使用注解的方式,为什么可以百度一下原因。hibernate自身不是自动提交的,需要自己手动开启事物 持久操作 然后 commit,当hibernate由spring管理之后,就是自动的了,不要手动开启 提交

我尝试把注释事务去掉,保留那个配置形式的事务,但还是不行!我的ORM,SPRING BEAN都是注释配置的

我是用你的配置写了个简单的例子。没有问题。
你是用的是什么架构?只是 spring +hibernate吗?没有使用其他的例如spring mvc 之类的吗?

有人,里面有用到@Controler,这个就是Action

@Controller
@RequestMapping(value="/test")
public class TestAction {
	private final Log log = LogFactory.getLog(TestAction.class);
	@Resource(name="roomService")
	private RoomServiceImpl roomService;


	public RoomService getRoomService() {
		return roomService;
	}


	public void setRoomService(RoomServiceImpl roomService) {
		this.roomService = roomService;
	}


	@RequestMapping(value="/test.htm")
	public String test(HttpServletRequest request){
		log.debug("----roomServier si : " + roomService);
		log.info("----roomServier si : " + roomService);
		log.info(roomService.get(1));
		Room room = new Room();
		room.setName("room1");
		//roomService.add(room);
		//roomService.addTest(room);
		roomService.get(room);
		return "test/test";
	}
}
引用 9 楼 archy123 的回复:
Quote: 引用 8 楼 tangtangzizi 的回复:
Quote: 引用 3 楼 qiangan7788 的回复:

建议在配置事物管理的时候,不要使用注解的方式,为什么可以百度一下原因。hibernate自身不是自动提交的,需要自己手动开启事物 持久操作 然后 commit,当hibernate由spring管理之后,就是自动的了,不要手动开启 提交

我尝试把注释事务去掉,保留那个配置形式的事务,但还是不行!我的ORM,SPRING BEAN都是注释配置的

百度回答你吗的把我回复给隐藏了。。
把你配置文件中这段删除  hibernate.current_session_context_class=org.springframework.orm.hibernate4.SpringSessionContext

我这个配置是从以前的项目复制回来的,以前这么写是可以的,不过以前是struts + spring + hibernate
除了没有struts包之外,其他包连版本都是一样的,没有更新过,是spring3+hibernate4,只是我觉得struts2的mvc用起来比较麻烦就去掉了。
另外就是学习尝试用注解的方式去设置配置,包括hibernate的orm也是。就是这些被改变,其他都一样。

引用 13 楼 tangtangzizi 的回复:
Quote: 引用 9 楼 archy123 的回复:
Quote: 引用 8 楼 tangtangzizi 的回复:
Quote: 引用 3 楼 qiangan7788 的回复:

建议在配置事物管理的时候,不要使用注解的方式,为什么可以百度一下原因。hibernate自身不是自动提交的,需要自己手动开启事物 持久操作 然后 commit,当hibernate由spring管理之后,就是自动的了,不要手动开启 提交

我尝试把注释事务去掉,保留那个配置形式的事务,但还是不行!我的ORM,SPRING BEAN都是注释配置的

百度回答你吗的把我回复给隐藏了。。
把你配置文件中这段删除  hibernate.current_session_context_class=org.springframework.orm.hibernate4.SpringSessionContext

我这个配置是从以前的项目复制回来的,以前这么写是可以的,不过以前是struts + spring + hibernate
除了没有struts包之外,其他包连版本都是一样的,没有更新过,是spring3+hibernate4,只是我觉得struts2的mvc用起来比较麻烦就去掉了。
另外就是学习尝试用注解的方式去设置配置,包括hibernate的orm也是。就是这些被改变,其他都一样。

刚发现 我没有看到你的spring 包目录自动扫描配置
例如:  
    <context:component-scan base-package=”com.xx”/>

你回滚的条件是抛出Exception  

代码就需要加上
try {

} catch (Exception e) {

}


40分
另外。
@EnableTransactionManagement and <tx:annotation-driven/> only looks for @Transactional on beans in the same application context they are defined in. This means that, if you put annotation driven configuration in a WebApplicationContext for a DispatcherServlet, it only checks for @Transactional beans in your controllers, and not your services. See Section 17.2, “The DispatcherServlet” for more information.
这是官网的提示。
它查找application context they are defined in 。并且不能定义到DispatcherServlet
所以包扫描必不可少
<aop:config proxy-target-class="true">
		<aop:advisor pointcut="execution(* com.framework.base.service.*.*(..))" advice-ref="txAdvice"/>
		<aop:advisor pointcut="execution(* com.*.service.*.*(..))" advice-ref="txAdvice"/>
	</aop:config>
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="save*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
			<tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
			<tx:method name="delete*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
			<tx:method name="get*" read-only="true"/>
			<tx:method name="query*" read-only="true"/>
			<tx:method name="pageQuery" read-only="true"/>
			<tx:method name="*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
		</tx:attributes>
	</tx:advice>

给楼主个参考

引用 17 楼 halee321 的回复:
<aop:config proxy-target-class="true">
		<aop:advisor pointcut="execution(* com.framework.base.service.*.*(..))" advice-ref="txAdvice"/>
		<aop:advisor pointcut="execution(* com.*.service.*.*(..))" advice-ref="txAdvice"/>
	</aop:config>
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="save*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
			<tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
			<tx:method name="delete*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
			<tx:method name="get*" read-only="true"/>
			<tx:method name="query*" read-only="true"/>
			<tx:method name="pageQuery" read-only="true"/>
			<tx:method name="*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
		</tx:attributes>
	</tx:advice>

给楼主个参考

我就是这么配置的啊,上面贴出了配置列表

引用 16 楼 archy123 的回复:

另外。
@EnableTransactionManagement and <tx:annotation-driven/> only looks for @Transactional on beans in the same application context they are defined in. This means that, if you put annotation driven configuration in a WebApplicationContext for a DispatcherServlet, it only checks for @Transactional beans in your controllers, and not your services. See Section 17.2, “The DispatcherServlet” for more information.
这是官网的提示。
它查找application context they are defined in 。并且不能定义到DispatcherServlet
所以包扫描必不可少

主要是我还有一个applicationContext.xml配置文件
里面写了一句:<context:component-scan base-package=”funs.el.mvc.*”
      resource-pattern=”*.class”></context:component-scan>
这句估计将我的dao和service都扫描了吧?不然他怎么注入?

而且,关键是我将事务相关的配置都注释了之后,add或者get(里面写了一个dao.add..测试)方法都可以插入到数据库。。
着是为什么啊~~?

引用 19 楼 tangtangzizi 的回复:
Quote: 引用 16 楼 archy123 的回复:

另外。
@EnableTransactionManagement and <tx:annotation-driven/> only looks for @Transactional on beans in the same application context they are defined in. This means that, if you put annotation driven configuration in a WebApplicationContext for a DispatcherServlet, it only checks for @Transactional beans in your controllers, and not your services. See Section 17.2, “The DispatcherServlet” for more information.
这是官网的提示。
它查找application context they are defined in 。并且不能定义到DispatcherServlet
所以包扫描必不可少

主要是我还有一个applicationContext.xml配置文件
里面写了一句:<context:component-scan base-package=”funs.el.mvc.*”
      resource-pattern=”*.class”></context:component-scan>
这句估计将我的dao和service都扫描了吧?不然他怎么注入?

而且,关键是我将事务相关的配置都注释了之后,add或者get(里面写了一个dao.add..测试)方法都可以插入到数据库。。
着是为什么啊~~?

不知道你的包结构是什么样的。mvc 和spring的扫描是不是冲突了?
你看下。spring 注入需要的是 dao service 。mvc需要的是Controller。
我最开始做的时候也没有注意这个事情,结果导致事务无法提交。

应该显式地抛出RuntimeException,然后ollback-for=RuntimeException,这样试试
我测试了下以前的项目。
显示声明readonly=true ,然后可以提交数据库。
http://www.ibm.com/developerworks/java/library/j-ts1/index.html
它有这么一段话。

@Transactional(readOnly = true, propagation=Propagation.REQUIRED)
public long insertTrade(TradeData trade) throws Exception {
   em.persist(trade);
   return trade.getTradeId();
}

Does the insertTrade() method in Listing 7:
Throw a read-only connection exception
Correctly insert the trade order and commit the data
Do nothing because the readOnly flag is set to true
The answer to this question is a bit more tricky. In some cases the answer is C, but in most cases (particularly when using JPA) the answer is B. The trade order is correctly inserted into the database without error. Wait a minute — the preceding example shows that a read-only connection exception would be thrown when the REQUIRED propagation mode is used. That is true when you use JDBC. However, when you use an ORM-based framework, the read-only flag works a bit differently. When you are generating a key on an insert, the ORM framework will go to the database to obtain the key and subsequently perform the insert. For some vendors, such as Hibernate, the flush mode will be set to MANUAL, and no insert will occur for inserts with non-generated keys. The same holds true for updates. However, other vendors, like TopLink, will always perform inserts and updates when the read-only flag is set to true. Although this is both vendor and version specific, the point here is that you cannot be guaranteed that the insert or update will not occur when the read-only flag is set, particularly when using JPA as it is vendor-agnostic.
你可以看看

引用 20 楼 archy123 的回复:
Quote: 引用 19 楼 tangtangzizi 的回复:
Quote: 引用 16 楼 archy123 的回复:

另外。
@EnableTransactionManagement and <tx:annotation-driven/> only looks for @Transactional on beans in the same application context they are defined in. This means that, if you put annotation driven configuration in a WebApplicationContext for a DispatcherServlet, it only checks for @Transactional beans in your controllers, and not your services. See Section 17.2, “The DispatcherServlet” for more information.
这是官网的提示。
它查找application context they are defined in 。并且不能定义到DispatcherServlet
所以包扫描必不可少

主要是我还有一个applicationContext.xml配置文件
里面写了一句:<context:component-scan base-package=”funs.el.mvc.*”
      resource-pattern=”*.class”></context:component-scan>
这句估计将我的dao和service都扫描了吧?不然他怎么注入?

而且,关键是我将事务相关的配置都注释了之后,add或者get(里面写了一个dao.add..测试)方法都可以插入到数据库。。
着是为什么啊~~?

不知道你的包结构是什么样的。mvc 和spring的扫描是不是冲突了?
你看下。spring 注入需要的是 dao service 。mvc需要的是Controller。
我最开始做的时候也没有注意这个事情,结果导致事务无法提交。

你发送一条短信给我你的QQ,我加你,然后我将项目和数据库发你,你看下是怎么回事吧!

引用 21 楼 peterandy110110 的回复:

应该显式地抛出RuntimeException,然后ollback-for=RuntimeException,这样试试

已经做过了。。

楼主解决了没呢,我也是这样的问题 使用是 hibernate4+spring3.2+springMVC, dao,service,model,controller 都是在MVC的配置文件里面的注解的,spring里面配置了事务,数据就是不能提交到数据库,加上手动的flush就可以了,怎么回事

CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明Spring 3 + Hibernate4 事务不成功