Spring学习之Transaciton+MyBatis+MySql+Maven+SringAOP(介绍+实例)

事务概念
一个数据库事务通常包含对数据库进行读或写的一个操作序列。

特性
并非任意的对数据库的操作序列都是数据库事务。事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。

原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。
一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束。拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。
持久性(Durability):一个事务一旦提交,他对数据库的修改应该永久保存在数据库中。

以上介绍完事务的四大特性(简称ACID),现在重点来说明下事务的隔离性,当多个线程都开启事务操作数据库中的数据时,数据库系统要能进行隔离操作,以保证各个线程获取数据的准确性,在介绍数据库提供的各种隔离级别之前,我们先看看如果不考虑事务的隔离性,会发生的几种问题:

1,脏读
  脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。

  当一个事务正在多次修改某个数据,而在这个事务中这多次的修改都还未提交,这时一个并发的事务来访问该数据,就会造成两个事务得到的数据不一致。例如:用户A向用户B转账100元,对应SQL命令如下

update account set money=money+100 where name=’B’;  (此时A通知B)

update account set money=money - 100 where name=’A’;

  当只执行第一条SQL时,A通知B查看账户,B发现确实钱已到账(此时即发生了脏读),而之后无论第二条SQL是否执行,只要该事务不提交,则所有操作都将回滚,那么当B以后再次查看账户时就会发现钱其实并没有转。

2,不可重复读
  不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。

  例如事务T1在读取某一数据,而事务T2立马修改了这个数据并且提交事务给数据库,事务T1再次读取该数据就得到了不同的结果,发送了不可重复读。

  不可重复读和脏读的区别是,脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。

  在某些情况下,不可重复读并不是问题,比如我们多次查询某个数据当然以最后查询得到的结果为主。但在另一些情况下就有可能发生问题,例如对于同一个数据A和B依次查询就可能不同,A和B就可能打起来了……

3,虚读(幻读)
  幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。也就是说:事务一执行了两次相同的查询操作。但是两次操作中间事务二向数据库中增加了一条符合事务一的查询条件的数据,导致幻读。

  幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。

  现在来看看MySQL数据库为我们提供的四种隔离级别:

  ① Serializable (串行化):可避免脏读、不可重复读、幻读的发生。

  ② Repeatable read (可重复读):可避免脏读、不可重复读的发生。

  ③ Read committed (读已提交):可避免脏读的发生。

  ④ Read uncommitted (读未提交):最低级别,任何情况都无法保证。

上面是数据库的事务下面介绍Spring的事务。

Spring事务隔离级别(isolation)
隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义了五个表示隔离级别的常量:
TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读和不可重复读,因此很少使用该隔离级别。
TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。即使在多次查询之间有新增的数据满足该查询,这些新增的记录也会被忽略。该级别可以防止脏读和不可重复读。
TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

事务传播行为(propagation)
所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:
TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
这里需要指出的是,前面的六种事务传播行为是 Spring 从 EJB 中引入的,他们共享相同的概念。而 PROPAGATION_NESTED是 Spring 所特有的。以 PROPAGATION_NESTED 启动的事务内嵌于外部事务中(如果存在外部事务的话),此时,内嵌事务并不是一个独立的事务,它依赖于外部事务的存在,只有通过外部的事务提交,才能引起内部事务的提交,嵌套的子事务不能单独提交。如果熟悉 JDBC 中的保存点(SavePoint)的概念,那嵌套事务就很容易理解了,其实嵌套的子事务就是保存点的一个应用,一个事务中可以包括多个保存点,每一个嵌套子事务。另外,外部事务的回滚也会导致嵌套子事务的回滚。

事务超时(timeout)
所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。

事务的只读属性(read-only)
事务的只读属性是指,对事务性资源进行只读操作或者是读写操作。所谓事务性资源就是指那些被事务管理的资源,比如数据源、 JMS 资源,以及自定义的事务性资源等等。如果确定只对事务性资源进行只读操作,那么我们可以将事务标志为只读的,以提高事务处理的性能。在 TransactionDefinition 中以 boolean 类型来表示该事务是否只读。

事务的回滚规则(rollback-for)
通常情况下,如果在事务中抛出了未检查异常(继承自 RuntimeException 的异常),则默认将回滚事务。如果没有抛出任何异常,或者抛出了已检查异常,则仍然提交事务。这通常也是大多数开发者希望的处理方式,也是 EJB 中的默认处理方式。但是,我们可以根据需要人为控制事务在抛出某些未检查异常时任然提交事务,或者在抛出某些已检查异常时回滚事务.

下面是Spring整合MyBatis的实例,声明式事务管理
准备工作:
1.数据库脚本:

ROP TABLE IF EXISTS `user`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `user` (
  `id` int(11) NOT NULL,
  `name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `user`
--

LOCK TABLES `user` WRITE;
/*!40000 ALTER TABLE `user` DISABLE KEYS */;
INSERT INTO `user` VALUES (1,'mike'),(2,'mike2'),(3,'mike3'),(4,'mike4'),(5,'mike5'),(6,'mike6'),(7,'huang'),(8,'huang');

2.maven配置文件pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>SpringTransaction</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>SpringTransaction Maven Webapp</name>
    <url>http://maven.apache.org</url>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>4.3.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.3.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>4.3.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.5.0</version>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2</version>
        </dependency>
        <dependency>
            <groupId>asm</groupId>
            <artifactId>asm</artifactId>
            <version>3.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.7.3</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.7.3</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.0.5</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.1</version>
        </dependency>

        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6.1</version>
        </dependency>
        <dependency>
            <groupId>antlr</groupId>
            <artifactId>antlr</artifactId>
            <version>2.7.7</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.2.3</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.2.1</version>
        </dependency>
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>3.0.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.2.1</version>
        </dependency>
    </dependencies>
    <build>
        <finalName>SpringMVC_RESTful</finalName>
    </build>
</project>

3.实体类User.java

public class User {
    private int id;
    private String name;

    public User() {

    }

    public User(int id, String name) {
        super();
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User [id=" + id + ", name=" + name + "]";
    }



}

4.DAO类UserDao.java

public interface UserDao {
        public int countAll();
        public void insertUser(User user);
        public List<User> getAllUser();
        public User getById(String id);
        public void deleteUser(String id);
        public void updateUser(@Param("id") int id, @Param("student") User user);
}

5.基于注解的DAO实现类UserDaoImpl.java
关于注解,看我以前的一篇博客:点击这里

@Repository("userDao")
public class UserDaoImpl implements UserDao{

    @Autowired
    private UserDao userDao;
    public int countAll() {
        return userDao.countAll();
    }

    public void insertUser(User user) {
        userDao.insertUser(user);
    }

    public List<User> getAllUser() {
        return userDao.getAllUser();
    }

    public User getById(String id) {
        return userDao.getById(id);
    }

    public void deleteUser(String id) {
        userDao.deleteUser(id);
    }


    public void updateUser(int id, User user) {

    }

}

6.service类UserService.java

public interface UserService {
    public int countAll();
    public void insertUser(User user);
    public List<User> getAllUser();
    public User getById(String id);
    public void deleteUser(String id);
    public void updateUser(int id, User user);
    public void update_insert(int id, User inerstUser,User updateUser);//用来测试事务的方法
}

7.service实现类UserServiceImpl.java

@Service("userService")
public class UserServiceImpl implements UserService{
    @Autowired
    private UserDao userDao;

    public int countAll() {
        return userDao.countAll();
    }

    public void insertUser(User user) {
        userDao.insertUser(user);

        throw new RuntimeException("Error");
    }

    public List<User> getAllUser() {
        return userDao.getAllUser();
    }

    public User getById(String id) {
        return userDao.getById(id);
    }

    public void deleteUser(String id) {
        userDao.deleteUser(id);
    }

    public void updateUser(int id, User user) {
        userDao.updateUser(id, user);
    }

    public void update_insert(int id, User insertUser, User updateUser) {
        userDao.updateUser(id, updateUser);
        userDao.insertUser(insertUser);
        throw new RuntimeException("Error");
    }


}

8.AOP日志类UserLogger.java

@Aspect
public class UserLogger {
    @Pointcut("execution(* com.example.service.impl.UserServiceImpl..*(..))")
    public void pointCut() {

    }

    @Before("pointCut()") 
    public void before(JoinPoint joinPoint) {
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        System.out.println(" before call :" + className + "---->" + methodName);  
    }

    @After("pointCut()") 
    public void after(JoinPoint joinPoint) {
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        System.out.println(" after method:" + className + "---->" + methodName);  
    }
    /*@Around("pointCut()") 
    public Object around(ProceedingJoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        Object object = null;
        //也可以执行
        this.before(joinPoint);
        try {
            object = joinPoint.proceed(args);
        } catch (Throwable e) {
            e.printStackTrace();
        }
        System.out.println("around method..");

        return object;

    }*/
}

下面是项目配置文件
9.数据库配置文件config.properties
一定注意用户名和密码后面不能有空格

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/testtransaction?characterEncoding=GBK
jdbc.username=root
jdbc.password=root
#
jdbc.initialPoolSize=20
jdbc.maxIdleTime=60
jdbc.maxPoolSize=200
jdbc.minPoolSize=10
#
jdbc.acquireIncrement=3
jdbc.acquireRetryDelay=1000
jdbc.acquireRetryAttempts=30
jdbc.breakAfterAcquireFailure=false

10.MyBatis配置文件mybatis-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <mappers>
        <mapper resource="MyBatis/UserMapper.xml"/>
    </mappers>
</configuration>

11.MyBatis实体映射文件UserMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.dao.UserDao">
    <resultMap type="com.example.entity.User" id="userList">
        <id property="id" column="id" javaType="java.lang.Integer" />
        <result property="name" column="name" javaType="java.lang.String" />
    </resultMap>

    <insert id="insertUser" parameterType="com.example.entity.User">
        insert into user(id,name) values(#{id},#{name})
    </insert>

    <select id="countAll" resultType="int">
        select count(*) from user
    </select>

    <select id="getAllUser" resultMap="userList">
        select * from user
    </select>

    <select id="getById" parameterType="int" resultType="com.example.entity.User">
        select * from user where id=#{id}
    </select>

    <delete id="deleteUser" parameterType="int">
        delete from user where id=#{id}
    </delete>

    <update id="updateUser" parameterType="com.example.entity.User">
        update user set name=#{user.name} where id=#{id}
    </update>
</mapper>

下面是Spring的配置文件applicationContext.xml
由于实现方式不同配置也有一定差异。
1.基于AOP使用tx标签
<tx:advice>:事务通知定义,用于指定事务属性,其中“transaction-manager”属性指定事务管理器,并通过< tx:attributes >指定具体需要拦截的方法;
<tx:method name="save*">:表示将拦截以save开头的方法,被拦截的方法将应用配置的事务属性:propagation=”REQUIRED”表示传播行为是Required,isolation=”READ_COMMITTED”表示隔离级别是提交读;
<tx:method name="*">:表示将拦截其他所有方法,被拦截的方法将应用配置的事务属性:propagation=”REQUIRED”表示传播行为是Required,isolation=”READ_COMMITTED”表示隔离级别是提交读,read-only=”true”表示事务只读;
<aop:config>:AOP相关配置:
<aop:pointcut/>:切入点定义,定义名为”serviceMethod”的aspectj切入点,切入点表达式为”execution(* com.example.service.impl..(..))”表示拦截con包及子包下的example.service.impl包及子包下的任何类的任何方法;
<aop:advisor>:Advisor定义,其中切入点为serviceMethod,通知为txAdvice。
从配置中可以看出,将对cn包及子包下的chapter9. service包及子包下的任何类的任何方法应用“txAdvice”通知指定的事务属性。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    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" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:util="http://www.springframework.org/schema/util" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:cache="http://www.springframework.org/schema/cache"
    xsi:schemaLocation="  
    http://www.springframework.org/schema/context  
    http://www.springframework.org/schema/context/spring-context.xsd  
    http://www.springframework.org/schema/beans  
    http://www.springframework.org/schema/beans/spring-beans.xsd  
    http://www.springframework.org/schema/tx  
    http://www.springframework.org/schema/tx/spring-tx.xsd  
    http://www.springframework.org/schema/jdbc  
    http://www.springframework.org/schema/jdbc/spring-jdbc-4.1.xsd  
    http://www.springframework.org/schema/cache  
    http://www.springframework.org/schema/cache/spring-cache-4.1.xsd  
    http://www.springframework.org/schema/aop  
    http://www.springframework.org/schema/aop/spring-aop.xsd  
    http://www.springframework.org/schema/util  
    http://www.springframework.org/schema/util/spring-util.xsd">

    <context:annotation-config />
    <context:component-scan base-package="com.example" />  <!-- 自动扫描 -->
    <aop:aspectj-autoproxy />
    <!-- 加载数据源配置文件 -->
    <context:property-placeholder location="MySql/config.properties" />

    <bean id="aspectJLogger" class="com.example.aop.UserLogger">
    </bean>

    <!-- 第一种配置数据源的方式 -->
    <!-- <bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url"
            value="jdbc:mysql://localhost:3306/testtransaction?characterEncoding=GBK" />
        <property name="username" value="root" />
        <property name="password" value="root" />
    </bean>
    -->

    <!-- 第二种配置数据源的方式  从properties文件读取-->
    <bean id="dataSource" 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>

    <!-- ================================事务相关控制================================================= -->
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!-- 第一种,使用tx标签方式 -->
    <tx:advice id="userTxAdvice" transaction-manager="transactionManager"> 
        <tx:attributes> <tx:method name="delete*" propagation="REQUIRED" read-only="false" 
        rollback-for="java.lang.Exception" no-rollback-for="java.lang.RuntimeException" 
        /> <tx:method name="insert*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" 
        /> <tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" 
        /> <tx:method name="find*" propagation="SUPPORTS" /> <tx:method name="get*" 
        propagation="SUPPORTS" /> <tx:method name="select*" propagation="SUPPORTS" 
        /> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut expression="execution(* 
        com.example.service.impl.*.*(..))" id="userLoggerService" /> <aop:advisor 
        pointcut-ref="userLoggerService" advice-ref="userTxAdvice" /> </aop:config> 

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--dataSource属性指定要用到的连接池 -->
        <property name="dataSource" ref="dataSource" />
        <!--configLocation属性指定mybatis的核心配置文件 -->
        <property name="configLocation" value="MyBatis/mybatis-config.xml" />
    </bean>

    <bean id="userDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
        <!--sqlSessionFactory属性指定要用到的SqlSessionFactory实例 -->
        <property name="sqlSessionFactory" ref="sqlSessionFactory" />
        <!--mapperInterface属性指定映射器接口,用于实现此接口并生成映射器对象 -->
        <property name="mapperInterface" value="com.example.dao.UserDao" />
    </bean>
</beans>

<tx:advice/>配置详解
<tx:advice>:id用于指定此通知的名字, transaction-manager用于指定事务管理器,默认的事务管理器名字为“transactionManager”;
<tx:method>:用于定义事务属性即相关联的方法名;
name:定义与事务属性相关联的方法名,将对匹配的方法应用定义的事务属性,可以使用“”通配符来匹配一组或所有方法,如“save”将匹配以save开头的方法,而“*”将匹配所有方法;
propagation:事务传播行为定义,默认为“REQUIRED”,表示Required,其值可以通过TransactionDefinition的静态传播行为变量的“PROPAGATION_”后边部分指定,如“TransactionDefinition.PROPAGATION_REQUIRED”可以使用“REQUIRED”指定;
isolation:事务隔离级别定义;默认为“DEFAULT”,其值可以通过TransactionDefinition的静态隔离级别变量的“ISOLATION_”后边部分指定,如“TransactionDefinition. ISOLATION_DEFAULT”可以使用“DEFAULT”指定:
timeout:事务超时时间设置,单位为秒,默认-1,表示事务超时将依赖于底层事务系统;
read-only:事务只读设置,默认为false,表示不是只读;
rollback-for:需要触发回滚的异常定义,以“,”分割,默认任何RuntimeException 将导致事务回滚,而任何Checked Exception 将不导致事务回滚;异常名字定义和TransactionProxyFactoryBean中含义一样
no-rollback-for:不被触发进行回滚的 Exception(s);以“,”分割;异常名字定义和TransactionProxyFactoryBean中含义一样;

2.基于注解@Transactional
这里的话UserServiceImpl.java有点不一样,会在方法头上加注解@Transactional

@Service("userService")
public class UserServiceImpl implements UserService{
    @Autowired
    private UserDao userDao;

    public int countAll() {
        return userDao.countAll();
    }

    @Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.READ_COMMITTED)
    public void insertUser(User user) {
        userDao.insertUser(user);

        throw new RuntimeException("Error");
    }

    public List<User> getAllUser() {
        return userDao.getAllUser();
    }

    public User getById(String id) {
        return userDao.getById(id);
    }

    public void deleteUser(String id) {
        userDao.deleteUser(id);
    }

    public void updateUser(int id, User user) {
        userDao.updateUser(id, user);
    }

    @Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.READ_COMMITTED)
    public void update_insert(int id, User insertUser, User updateUser) {
        userDao.updateUser(id, updateUser);
        userDao.insertUser(insertUser);
        throw new RuntimeException("Error");
    }


}

Spring配置文件applicationContext.xml也有一定差异

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    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" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:util="http://www.springframework.org/schema/util" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:cache="http://www.springframework.org/schema/cache"
    xsi:schemaLocation="  
    http://www.springframework.org/schema/context  
    http://www.springframework.org/schema/context/spring-context.xsd  
    http://www.springframework.org/schema/beans  
    http://www.springframework.org/schema/beans/spring-beans.xsd  
    http://www.springframework.org/schema/tx  
    http://www.springframework.org/schema/tx/spring-tx.xsd  
    http://www.springframework.org/schema/jdbc  
    http://www.springframework.org/schema/jdbc/spring-jdbc-4.1.xsd  
    http://www.springframework.org/schema/cache  
    http://www.springframework.org/schema/cache/spring-cache-4.1.xsd  
    http://www.springframework.org/schema/aop  
    http://www.springframework.org/schema/aop/spring-aop.xsd  
    http://www.springframework.org/schema/util  
    http://www.springframework.org/schema/util/spring-util.xsd">

    <context:annotation-config />
    <context:component-scan base-package="com.example" />  <!-- 自动扫描 -->
    <aop:aspectj-autoproxy />
    <!-- 加载数据源配置文件 -->
    <context:property-placeholder location="MySql/config.properties" />

    <bean id="aspectJLogger" class="com.example.aop.UserLogger">
    </bean>

    <!-- 第一种配置数据源的方式 -->
    <!-- <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url"
            value="jdbc:mysql://localhost:3306/testtransaction?characterEncoding=GBK" />
        <property name="username" value="root" />
        <property name="password" value="root" />
    </bean>
    -->

    <!-- 第二种配置数据源的方式  从properties文件读取-->
    <bean id="dataSource" 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>

    <!-- ================================事务相关控制================================================= -->
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!-- 第二种配置事务的方式,注解 -->
    <tx:annotation-driven transaction-manager="transactionManager" />

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--dataSource属性指定要用到的连接池 -->
        <property name="dataSource" ref="dataSource" />
        <!--configLocation属性指定mybatis的核心配置文件 -->
        <property name="configLocation" value="MyBatis/mybatis-config.xml" />
    </bean>

    <bean id="userDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
        <!--sqlSessionFactory属性指定要用到的SqlSessionFactory实例 -->
        <property name="sqlSessionFactory" ref="sqlSessionFactory" />
        <!--mapperInterface属性指定映射器接口,用于实现此接口并生成映射器对象 -->
        <property name="mapperInterface" value="com.example.dao.UserDao" />
    </bean>
</beans>

参考文献:基础参考:
点击这里
点击这里
点击这里

demo参考:点击这里

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值