zoukankan      html  css  js  c++  java
  • 马士兵Spring-声明式事务管理-annotation

    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);
        }
    
    }
    View Code

    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!");
        }
    
    }
    View Code

    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;
        }
        
    }
    View Code

    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;
        }
    }
    View Code

    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();
        }
    }
    View Code

    测试结果:

    因为在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了;

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

  • 相关阅读:
    Android 解决小米手机Android Studio安装app 报错的问题It is possible that this issue is resolved by uninstalling an existi
    Android Unresolved Dependencies
    Android studio 自定义打包apk名
    Android Fragment与Activity交互的几种方式
    魅族和三星Galaxy 5.0webView 问题Android Crash Report
    Android几种常见的多渠道(批量)打包方式介绍
    Android批量打包 如何一秒内打完几百个apk渠道包
    上周热点回顾(9.30-10.6)团队
    上周热点回顾(9.23-9.29)团队
    上周热点回顾(9.16-9.22)团队
  • 原文地址:https://www.cnblogs.com/tenWood/p/6892009.html
Copyright © 2011-2022 走看看