spring手动提交事务+hibernate事务不提交,为什么

细谈Spring(九)spring+hibernate声明式事务管理详解_java那些事_【传送门】
细谈Spring(九)spring+hibernate声明式事务管理详解
声明式事务管理是对事务管理的最常用的方式,因为这种方式对代码的影响最小,因此也符合非侵入性的轻量级容器的概念。的事务管理是通过的方式来实现的,因为事务方面的代码与的绑定并以一种样板式结构使用。在理解声明式事务管理我们首先要理解他是通过怎么具体实现的。其中的事务通知由元数据(目前基于和注解)驱动。代理对象由元数据结合产生一个新的代理对象。他使用一个实现配合在方法调用之前实施事务。下面我们就通过一个图来看一下声明式事务管理的执行过程。
下面我们就以一个官方文档所给的例子来具体看一下用配置方式怎么来实现声明式事务管理:首先请看下面的接口和它的实现。这个例子的意图是介绍概念:// 我们想做成事务性的服务接口[java]view plaincopyprint?package x.y.
public interface FooService {
Foo getFoo(String fooName);
Foo getFoo(String fooName, String barName);
void insertFoo(Foo foo);
void updateFoo(Foo foo);
// 上述接口的一个实现[java]view plaincopyprint?package x.y.
public class DefaultFooService implements FooService {
public Foo getFoo(String fooName) {
throw new UnsupportedOperationException();
public Foo getFoo(String fooName, String barName) {
throw new UnsupportedOperationException();
public void insertFoo(Foo foo) {
throw new UnsupportedOperationException();
public void updateFoo(Foo foo) {
throw new UnsupportedOperationException();
首先要解释的是很多同学可能都在考虑这个事务管理到底是放在层还是放在层呢。这个问题我想大多数童鞋的反应应该都是在层上吧,刚开始我也是这么想的。但是大家想想,如果我们要进行两个甚至多个层中的方法操作,并且要求放在同一个事务里时,我们该怎么来管理这个事务呢,这时我们就没办法了。所以我们应该把事务管理放在层中,我们直接在层中调用这两个层的方法就了。
下面我们接着往下看,我们假定,FooService的前两个方法(getFoo(String) 和getFoo(String, String))必须执行在只读事务上下文中,其他的方法(insertFoo(Foo)和 updateFoo(Foo))必须执行在可读写事务上下文中。我们根据这个要求来看一下配置文件,我们刚开始可能看不懂,不用慌,往下我们会一一解释的。[html]view plaincopyprint?
version="1.0" encoding="UTF-8"
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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"
id="fooService" class="x.y.service.DefaultFooService"
id="txAdvice" transaction-manager="txManager"
name="get*" read-only="true"
<!-- ensure that the above transactional advice runs for any execution
of an operation defined by the FooService interface --
id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"
advice-ref="txAdvice" pointcut-ref="fooServiceOperation"
id="dataSource" class="mons.dbcp.BasicDataSource" destroy-method="close"
name="driverClassName" value="oracle.jdbc.driver.OracleDriver"
name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"
name="username" value="scott"
name="password" value="tiger"
id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
name="dataSource" ref="dataSource"
好了,配置一大片,什么东西,我也看不懂,呵呵,没关系,一会大家就明白了,我们先来看一下官方给的解释,然后我在根据我自己的理解给大家通俗的解释一下这里的内容。
我们要把一个服务对象('fooService' bean)做成事务性的。 我们想施加的事务语义封装在定义中。 “把所有以 'get' 开头的方法看做执行在只读事务上下文中, 其余的方法执行在默认语义的事务上下文中”。 其中的 'transaction-manager' 属性被设置为一个指向 PlatformTransactionManager bean的名字(这里指 'txManager'), 该bean将会真正管理事务。配置中最后一段是
的定义, 它确保由 'txAdvice' bean定义的事务通知在应用中合适的点被执行。 首先我们定义了 一个切面,它匹配 FooService 接口定义的所有操作, 我们把该切面叫做 'fooServiceOperation'。然后我们用一个通知器(advisor)把这个切面与 'txAdvice' 绑定在一起, 表示当 'fooServiceOperation' 执行时,'txAdvice'
定义的通知逻辑将被执行。
好了,上面就是官方文档给出的这个配置文件的解释,不知道大家有没有看懂,反正对于初学者我的时候,我是真没看懂,不太容易懂,当然了,大牛们是一定能看懂的。下面我就根据我自己的理解来通俗的讲解一下。
首先我们应该要把服务对象'fooService' 声明成一个bean,我们要把一个服务对象('fooService' bean)做成事务性的。我们就应该首先在声明一个事务管理的建议,用什么来管理,spring给我们提供了事务封装,这个就封装在了中,这个事务建议给我们提供了一个transaction-manager属性,用他可以指定我们用谁来管理我们的事务。我们上边的例子用的为一个指向 PlatformTransactionManager bean的名字(这里指 'txManager'), 该将会真正管理事务。上面用的事务管理类是用的jdbc中提供的事务管理,当然这里也可以指定为管理。当然了,不管用那个类来管理我们的事务,都不要忘记了提供我们的属性,因为事务管理也需要这里面的信息。我们声明好事务建议,也指定好了具体用哪个类来管理了,下面我们的任务就是要把我们定义好的这些利用AOP把我们的事务管理织入到我们的业务逻辑里面了。 的定义, 它确保由 'txAdvice'
bean定义的事务通知在应用中合适的点被执行。 首先我们定义了 一个切面,它匹配 FooService 接口定义的所有操作, 我们把该切面叫做 'fooServiceOperation'。 元素定义是的切面表示法,上述表示x.y.service.FooService包下的任意方法。然后我们用一个通知器()把这个切面与 'txAdvice' 绑定在一起, 表示当 'fooServiceOperation' 执行时,'txAdvice' 定义的通知逻辑将被执行。大体流程就是这样的了。
上面的配置将为'fooService' bean创建一个代理对象,这个代理对象被装配了事务通知,所以当它的相应方法被调用时,一个事务将被启动、挂起、被标记为只读,或者其它(根据该方法所配置的事务语义)。我们来看看下面的例子,测试一下上面的配置。[java]view plaincopyprint?public final class Boot {
public static void main(final String[] args) throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("context.xml", Boot.class);
FooService fooService = (FooService) ctx.getBean("fooService");
fooService.insertFoo (new Foo());
运行可以清楚的看到如下结果:- Invoking rollback for transaction on x.y.service.FooService.insertFoo
due to throwable [java.lang.UnsupportedOperationException] 有关的设置通过 标签来指定不同的事务性设置。默认的 设置如下:事务传播设置是 隔离级别是事务是 读写事务超时默认是依赖于事务系统的,或者事务超时没有被支持。任何 将触发事务回滚,但是任何 将不触发事务回滚这些默认的设置当然也是可以被改变的。 和 标签里的 各种属性设置总结如下:Table 9.1.
有关的设置属性是否需要?默认值描述name是与事务属性关联的方法名。通配符()可以用来指定一批关联到相同的事务属性的方法。 如:、、等等。propagation不REQUIRED事务传播行为isolation不DEFAULT事务隔离级别timeout不-1事务超时的时间(以秒为单位)read-only不false事务是否只读?rollback-for不将被触发进行回滚的 ;以逗号分开。 如:no-rollback-for不不 被触发进行回滚的 ;以逗号分开。 如:下面我们具体来看一下事务的传播性的几个值:REQUIRED:业务方法需要在一个容器里运行。如果方法运行时,已经处在一个事务中,那么加入到这个事务,否则自己新建一个新的事务。NOT_SUPPORTED:声明方法不需要事务。如果方法没有关联到一个事务,容器不会为他开启事务,如果方法在一个事务中被调用,该事务会被挂起,调用结束后,原先的事务会恢复执行。REQUIRESNEW:不管是否存在事务,该方法总汇为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务挂起,新的事务被创建。MANDATORY:该方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果在没有事务的环境下被调用,容器抛出例外。SUPPORTS:该方法在某个事务范围内被调用,则方法成为该事务的一部分。如果方法在该事务范围外被调用,该方法就在没有事务的环境下执行。NEVER:该方法绝对不能在事务范围内执行。如果在就抛例外。只有该方法没有关联到任何事务,才正常执行。NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按属性执行。它使用了一个单独的事务,这个事务 拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对事务管理器起效。使用 @Transactional除了基于文件的声明式事务配置外,你也可以采用基于注解式的事务配置方法。直接在源代码中声明事务语义的做法让事务声明和将受其影响的代码距离更近了,而且一般来说不会有不恰当的耦合的风险,因为,使用事务性的代码几乎总是被部署在事务环境中。下面的例子很好地演示了 注解的易用性,随后解释其中的细节。先看看其中的类定义:[java]view plaincopyprint?
@Transactional
public class DefaultFooService implements FooService {
Foo getFoo(String fooName);
Foo getFoo(String fooName, String barName);
void insertFoo(Foo foo);
void updateFoo(Foo foo);
当上述的定义在容器里时,上述实例仅仅通过一 行配置就可以使它具有事务性的。如下:[html]view plaincopyprint? version="1.0" encoding="UTF-8"
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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"
id="fooService" class="x.y.service.DefaultFooService"
transaction-manager="txManager"
id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
name="dataSource" ref="dataSource"
实际上,如果你用 'transactionManager' 来定义 PlatformTransactionManager bean的名字的话,你就可以忽略
标签里的 'transaction-manager' 属性。 如果 PlatformTransactionManager bean你要通过其它名称来注入的话,你必须用 'transaction-manager' 属性来指定它。
在多数情形下,方法的事务设置将被优先执行。在下列情况下,例如: 类在类的级别上被注解为只读事务,但是,这个类中的 方法的 注解的事务设置将优先于类级别注解的事务设置。[html]view plaincopyprint?@Transactional(readOnly = true)
public class DefaultFooService implements FooService {
public Foo getFoo(String fooName) {
// do something
// these settings have precedence for this method
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void updateFoo(Foo foo) {
// do something
@Transactional 有关的设置@Transactional 注解是用来指定接口、类或方法必须拥有事务语义的元数据。 如:当一个方法开始调用时就开启一个新的只读事务,并停止掉任何现存的事务”。 默认的 设置如下:事务传播设置是 事务隔离级别是 事务是 读写事务超时默认是依赖于事务系统的,或者事务超时没有被支持。任何 将触发事务回滚,但是任何 将不触发事务回滚这些默认的设置当然也是可以被改变的。 注解的各种属性设置总结如下: @Transactional 注解的属性属性类型描述propagation枚举型:可选的传播性设置isolation枚举型:可选的隔离性级别(默认值:)readOnly布尔型读写型事务 只读型事务timeoutint型(以秒为单位)事务超时rollbackFor一组 类的实例,必须是的子类一组异常类,遇到时 必须 进行回滚。默认情况下不进行回滚,仅(即的子类)才进行事务回滚。rollbackForClassname一组 类的名字,必须是的子类一组异常类名,遇到时 必须 进行回滚noRollbackFor一组 类的实例,必须是的子类一组异常类,遇到时 必须不 回滚。noRollbackForClassname一组 类的名字,必须是的子类一组异常类,遇到时 必须不 回滚
在写代码的时候,不可能对事务的名字有个很清晰的认识,这里的名字是指会在事务监视器(比如的事务管理器)或者日志输出中显示的名字, 对于声明式的事务设置,事务名字总是全限定名事务通知的类的方法名。比如类的方法启动了一个事务,事务的名称是:com.foo.BusinessService.handlePayment
觉得不错,分享给更多人看到
java那些事 微信二维码
分享这篇文章
java那些事 最新文章
java那些事 热门文章spring3.2.5+hibernate4.1.11配置宣言事务后,不能自动提交,也就是还需要手动session.flush() - Web开发当前位置:& &&&spring3.2.5+hibernate4.1.11配置宣言事务后,不能spring3.2.5+hibernate4.1.11配置宣言事务后,不能自动提交,也就是还需要手动session.flush()&&网友分享于:&&浏览:0次spring3.2.5+hibernate4.1.11配置声明事务后,不能自动提交,也就是还需要手动session.flush()web.xml------:
&!--&从类路径下加载spring配置文件,classpath关键字特指类路径下加载&--&
&&&context-param&
&& &param-name&contextConfigLocation&/param-name&
&& &param-value&classpath:applicationContext.xml&/param-value&
&&&/context-param&
&&&!--&负责启动spring容器的监听器,它将引用上面的上下文参数获得spring配置文件地址&--&
&&&listener&
&& &listener-class&
org.springframework.web.context.ContextLoaderListener
&& &/listener-class&
&&&/listener&
&&&!--&负责在View层打开session(lazy&load)&--&
&&&filter&
&filter-name&hibernateFilter&/filter-name&
&filter-class&org.springframework.orm.hibernate4.support.OpenSessionInViewFilter&/filter-class&
&&&/filter&
&&&filter-mapping&
&filter-name&hibernateFilter&/filter-name&
&url-pattern&/*&/url-pattern&
&&&/filter-mapping&
&&&!--&spring的核心是DispatcherServlet,它负责控制整个页面的请求路劲&--&
&&&servlet&
&& &servlet-name&spring&/servlet-name&
&& &servlet-class&
org.springframework.web.servlet.DispatcherServlet
&& &/servlet-class&
&&&/servlet&
&&&!--拦截所有以html结尾的请求--&
&&&servlet-mapping&
&& &servlet-name&spring&/servlet-name&
&& &url-pattern&*.html&/url-pattern&
&&&/servlet-mapping&
&&&!--处理从页面传递中文到后台而出现的中文乱码问题--&
&&&filter&
&&&&&&&&&filter-name&encodingFilter&/filter-name&
&&&&&&&&&filter-class&
&&&&&&&& org.springframework.web.filter.CharacterEncodingFilter
&&&&&&&&&/filter-class&
&&&&&&&&&init-param&
&&&&&&&&&&&&&param-name&encoding&/param-name&
&&&&&&&&&&&&&param-value&UTF-8&/param-value&
&&&&&&&&&/init-param&
&&&/filter&
&&&filter-mapping&
&&&&&&&&&filter-name&encodingFilter&/filter-name&
&&&&&&&&&url-pattern&*&/url-pattern&
&&&/filter-mapping&
&&&!--&错误页面设置&--&
&&&error-page&
&error-code&404&/error-code&
&location&/404.htm&/location&
&&&/error-page&
&&&welcome-file-list&
&&&&&welcome-file&index.jsp&/welcome-file&
&&&/welcome-file-list&
applicationContext.xml------
&!--&扫描com下的所有类包,应用spring的注解配置&--&
&context:component-scan&base-package="com"/&
&&&&&!--&加载JDBC资源文件信息&--&
&context:property-placeholder&location="classpath:jdbc.properties"/&
&&&&&!--&获取数据源&--&
&&&&&bean&id="c3p0DataSource"&destroy-method="close"&class="com.mchange.boPooledDataSource"&
&&&& &!--&指定连接数据库的驱动&--&
&&&&&&& &property&name="driverClass"&value="${driver}"/&
&&&&&&& &!--&指定连接数据库的URL&--&
&&&&&&& &property&name="jdbcUrl"&value="${url}"/&
&&&&&&& &!--&指定连接数据库的用户名&--&
&&&&&&& &property&name="user"&value="${user}"/&
&&&&&&& &!--&指定连接数据库的密码&--&
&&&&&&& &property&name="password"&value="${password}"/&
&&&&&&& &property&name="maxPoolSize"&value="${maxPoolSize}"/&
&&&&&&& &property&name="minPoolSize"&value="${minPoolSize}"/&
&&&&&&& &property&name="initialPoolSize"&value="${initialPoolSize}"/&
&&&&&&& &property&name="maxIdleTime"&value="${maxIdleTime}"/&
&&&&&/bean&
&&&&&!--&定义Hibernate的SessionFactory&--&
&&&&&bean&id="sessionFactory"&
&&&& class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"&
&&&& &property&name="dataSource"&ref="c3p0DataSource"/&
&&&& &!--&基于注解类的配置&--&
&&&& &property&name="packagesToScan"&
&value&com.domain&/value& 共&2&页:
12345678910
12345678910
12345678910 上一篇:下一篇:文章评论相关解决方案 12345678910 Copyright & &&版权所有<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
您的访问请求被拒绝 403 Forbidden - ITeye技术社区
您的访问请求被拒绝
亲爱的会员,您的IP地址所在网段被ITeye拒绝服务,这可能是以下两种情况导致:
一、您所在的网段内有网络爬虫大量抓取ITeye网页,为保证其他人流畅的访问ITeye,该网段被ITeye拒绝
二、您通过某个代理服务器访问ITeye网站,该代理服务器被网络爬虫利用,大量抓取ITeye网页
请您点击按钮解除封锁&

我要回帖

更多关于 hibernate提交事务 的文章

 

随机推荐