1.事务加在DAO层还是service层?
service中可能多涉及多种DAO的操作,比如存了一个User之后,需要保存一条日志信息;如果在DAO中分别设置事务的话,一个DAO下面方法抛出异常了,但是不会影响到另一个DAO下面的方法,这是两个事务;因此事务要加在Service层;
 
2.需求:存一个user的同时,记录一个日志,说这个user被存了;
 
3.代码实现:--这边是spring管理hibernate下的transaction;
1)DAO实现:UserDAOImpl.java  --保存User 
package com.cy.dao.impl;

import javax.annotation.Resource;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.stereotype.Component; import com.cy.dao.UserDAO;
import com.cy.model.User; @Component
public class UserDAOImpl implements UserDAO { @Resource
private SessionFactory sessionFactory; //保存User
public void save(User user) {
Session s = sessionFactory.getCurrentSession();
s.save(user);
} }

2)DAO实现:LogDAOImpl.java  --保存Log

package com.cy.dao.impl;

import javax.annotation.Resource;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.stereotype.Component; import com.cy.dao.LogDAO;
import com.cy.model.Log; @Component("logDAO")
public class LogDAOImpl implements LogDAO { @Resource
private SessionFactory sessionFactory; //保存日志信息
public void save(Log log) {
Session s = sessionFactory.getCurrentSession();
s.save(log);
throw new RuntimeException("error!");
} }

3)User实体 和 Log实体:

User.java:

package com.cy.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id; @Entity
public class User {
private int id;
private String username;
private String password; @Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
} }

Log.java:

package com.cy.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table; /**
*
* @author chengyu
* 表名和我们的类名不一样,使用@Table(name="xxx");
*/
@Entity
@Table(name="t_log")
public class Log {
private int id;
private String msg; @Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}

4)UserService中保存User后,插入一条日志记录:

package com.cy.service;

import javax.annotation.Resource;

import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional; import com.cy.dao.LogDAO;
import com.cy.dao.UserDAO;
import com.cy.model.Log;
import com.cy.model.User; @Component("userService")
public class UserService { @Resource
private UserDAO userDAO; @Resource
private LogDAO logDAO; public void init() {
System.out.println("init");
} /**
* 插入一个用户的同时,记录一条日志
* @Transactional 默认情况:如果catch到任何的RuntimeException,自动回滚
*/
@Transactional
public void add(User user) {
userDAO.save(user);
Log log = new Log();
log.setMsg("a user saved!");
logDAO.save(log);
} public UserDAO getUserDAO() {
return userDAO;
} public void setUserDAO( UserDAO userDAO) {
this.userDAO = userDAO;
} public void destroy() {
System.out.println("destroy");
}
}

5)beans.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:context="http://www.springframework.org/schema/context"
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/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <context:annotation-config />
<context:component-scan base-package="com.cy"/> <!-- 如果下面使用到了占位符的方式,请在locations下面去找 -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<value>classpath:jdbc.properties</value>
</property>
</bean> <bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
<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> <!-- 初始化SessionFactory
annotatedClasses : 接收对那些类做了注解
-->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.cy.model.User</value>
<value>com.cy.model.Log</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean> <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean> <tx:annotation-driven transaction-manager="txManager"/> </beans>

6)测试代码:

package com.cy.service;

import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext; import com.cy.model.User; public class UserServiceTest { @Test
public void testAdd() throws Exception {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
UserService service = (UserService)ctx.getBean("userService");
System.out.println(service.getClass());
service.add(new User());
ctx.destroy();
}
}

测试结果:

因为在LogDAOImpl中插入日志时,throw new RuntimeException("error!");

User和Log都插入失败,User插入后回滚了;

4. @Transactional settings的配置:

事务的传播特性:在当前的执行环境里头,到底有没有事务,另外根据这个事务的配置情况执行到我这个当前方法的时候,当前这个方法怎么样来处理这个事务;
1.propagation:  transaction的产生过程;事务的传播方式;
REQUIRED:@Transactional注解的默认值; 如果有就使用原来的,如果没有就创建一个新的;@Transactional(propagation=Propagation.REQUIRED)
MANDATORY: 强制的,必须的;当前这个方法要执行,必须得有一个Transaction;如果没有transaction会抛异常;
     比如UserService中的add方法上面@Transactional(propagation=Propagation.MANDATORY),那么测试方法中调用此add方法之前,就必须得有一个transaction;
NESTED:在一个内嵌的transaction里面执行;
    原来有一个transaction了,相当于在这个里面内嵌了一个transaction,不在原来的transaction里面执行了,而是在内嵌的transaction里面执行, 内部的transaction回滚的时候不会影响外面的
transaction;
NEVER: 我这个方法要执行,必须不能有事务;要是有事务,抛异常;
NOT_SUPPORTED: 这个方法要想执行必须不能有事务;要是有事务把这个事务挂起,执行完我这个方法,原来的事务再继续;
REQUIRES_NEW:创建一新的transaction,如果当前有transaction,将此transaction挂起;
SUPPORTS: 支持当前的transaction,要是有我就有,要是没有我也就没有,就不在事务里执行; 2.isolation: 隔离级别;
3.readOnly: 如果设置为true,在transaction里面没有update。insert、delete这方面操作;比如上面的例子,add方法中要设置为@Transactional(readOnly=true)的话,就会报错:
Caused by: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed;
如果确认没有写的操作,可以设置为true,这时候spring会使用只读的Connection,readOnly的connection比读写的Connection执行效率要高;可以提高性能;
再者,如果这个方法里面规定只能读,那么可以设置为true,防止别人进行更改操作;
4.timeout: 一个事务如果时间太长的话,就把它终止掉;
5.rollbackFor: 默认情况下,RuntimeException会导致回滚;HibernateException本身就是一种运行期异常;
可以在rollbackFor里面写清楚,什么情况下会回滚,比如写自己定义的MyException,如果抛出MyException,就会回滚;
6.noRollbackFor: 在某些异常下不会回滚,其他的会回滚;
required图解:

在执行了method1,method1里面调用了method2,如果说在method1里面已经有transaction了,那么method2里面就不需要再创建新的transaction了;

---------------------

马士兵Spring-声明式事务管理-annotation的更多相关文章

  1. Spring声明式事务管理(基于注解方式实现)

    ----------------------siwuxie095                                 Spring 声明式事务管理(基于注解方式实现)         以转 ...

  2. spring 声明式事务管理

    简单理解事务: 比如你去ATM机取5000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉5000元钱:然后ATM出5000元钱.这两个步骤必须是要么都执行要么都不执行.如果银行卡扣除了5000块但 ...

  3. Spring声明式事务管理基于@Transactional注解

    概述:我们已知道Spring声明式事务管理有两种常用的方式,一种是基于tx/aop命名空间的xml配置文件,另一种则是基于@Transactional 注解.         第一种方式我已在上文为大 ...

  4. Spring声明式事务管理基于tx/aop命名空间

    目的:通过Spring AOP 实现Spring声明式事务管理; Spring支持编程式事务管理和声明式事务管理两种方式. 而声明式事务管理也有两种常用的方式,一种是基于tx/aop命名空间的xml配 ...

  5. XML方式实现Spring声明式事务管理

    1.首先编写一个实体类 public class Dept { private int deptId; private String deptName; public int getDeptId() ...

  6. Spring声明式事务管理(基于XML方式实现)

    --------------------siwuxie095                             Spring 声明式事务管理(基于 XML 方式实现)         以转账为例 ...

  7. Spring声明式事务管理与配置介绍

    转至:http://java.9sssd.com/javafw/art/1215 [摘要]本文介绍Spring声明式事务管理与配置,包括Spring声明式事务配置的五种方式.事务的传播属性(Propa ...

  8. 吴裕雄--天生自然JAVA SPRING框架开发学习笔记:Spring声明式事务管理(基于Annotation注解方式实现)

    在 Spring 中,除了使用基于 XML 的方式可以实现声明式事务管理以外,还可以通过 Annotation 注解的方式实现声明式事务管理. 使用 Annotation 的方式非常简单,只需要在项目 ...

  9. spring声明式事务管理方式( 基于tx和aop名字空间的xml配置+@Transactional注解)

    1. 声明式事务管理分类 声明式事务管理也有两种常用的方式, 一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解. 显然基于注解的方式更简单易用,更清爽. ...

  10. spring声明式事务管理总结

    事务配置 首先在/WEB-INF/applicationContext.xml添加以下内容: <!-- 配置事务管理器 --> <bean id="transactionM ...

随机推荐

  1. linux使用vi浏览python源码

    一.背景 2018/8/15,这一天要分析一个python项目,因此需要浏览代码,而我使用的是ubuntu 16.04,于是作此文 二.步骤 2.1 获取生成tags文件的脚本 http://svn. ...

  2. HDU6447 网络赛 YJJ's Salesman(DP + 线段树)题解

    思路:若用dp[i][j]表示走到(i,j)的最大值,那么dp[i][j] = max(dp[i - 1][j],dp[i][j - 1],dp[i - 1][j - 1] + v),显然O(n^2) ...

  3. Bootstrap and Angular

  4. Flask 5 模板1

    NOTE 1.VF的作用:生成请求的响应.一般来说请求会改变程序的状态,这种变化会在视图函数中产生. eg.用户在网站中注册了一个新账户,用户在表单中输入电子邮件地址和密码,然后提交到服务器,服务器接 ...

  5. python 简单的猜数字游戏

    !/usr/bin/env python --encoding:utf-8-- import random think=random.randint(1,10) print ("...... ...

  6. python fromkeys() 创建字典

    # d = dict.fromkeys("张无忌","赵敏") #创建字典 # print(d)#{'张': '赵敏', '无': '赵敏', '忌': '赵敏 ...

  7. Android反射机制:手把手教你实现反射

    什么是反射机制? JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称 ...

  8. OOP、AOP 、IoC和DI、ORM 概念

    OOP 面向对象编程(Object Oriented Programming) OOP引入封装.继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合. AOP 面向切面编程Aspect ...

  9. WPF 动画 和 色彩 的随笔

    1:善于用“Margin”做动画效果 2:色彩处理通常用:Brush,而Brush(如:SolidColorBrush)的实例化,通常需要载入“ System.Windows.Media.Color” ...

  10. BooStrap4文档摘录 2 Content, Component

    Content Reboot:从新写了主要元素的排列. 本章讲了各种元素及其相关的类. ⚠️ 文档左上角有搜索栏. Components Alert✅ Badge✅ Button✅和Button gr ...