spring采用@Transactional注解进行事务申明,@Transactional既可以在方法上申明,也可以在类上申明,方法申明优先于类申明。
1、pom配置
包括spring核心包引入以及spring jdbc包引入。
<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.coshaho</groupId> <artifactId>coshaho-model</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>coshaho-model</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <!-- https://mvnrepository.com/artifact/org.springframework/spring-core --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.1.4.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-context --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.1.4.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.13</version> </dependency> <!-- https://mvnrepository.com/artifact/c3p0/c3p0 --> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> </project>
2、spring.xml配置
需要引入tx标签,初始化DataSourceTransactionManager实例,并把@Transactional和DataSourceTransactionManager实例关联起来。
<?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:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd" > <!-- 注解注入 --> <context:component-scan base-package="com.coshaho.*" /> <!-- 引入jdbc配置文件 --> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 使用spring初始化DataSource --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driverClass}"></property> <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property> <property name="user" value="${jdbc.user}"></property> <property name="password" value="${jdbc.password}"></property> </bean> <!-- 使用JdbcTemplate封装DataSource --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 定义事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!--使用注释事务 --> <tx:annotation-driven transaction-manager="transactionManager" /> </beans>
3、测试代码
定义数据库表对象以及映射关系
package com.coshaho.vo; public class User { private int id; private String name; private int age; 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; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User [id=" + id + ", name=" + name + ", age=" + age + "]"; } }
package com.coshaho.dao; import java.sql.ResultSet; import java.sql.SQLException; import org.springframework.jdbc.core.RowMapper; import com.coshaho.vo.User; public class UserMapper implements RowMapper<User> { public User mapRow(ResultSet rs, int rowNum) throws SQLException { User user = new User(); user.setId(rs.getInt("id")); user.setName(rs.getString("name")); user.setAge(rs.getInt("age")); return user; } }
我们定义user表字段name为唯一字段,用事务代码插入两行相同记录,看看能否成功。
package com.coshaho.dao; import com.coshaho.vo.User; public interface UserDao { public void create(String name, int age); public User query(int id); public void create2User(); }
package com.coshaho.dao; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import com.coshaho.vo.User; @Component public class UserDaoImpl implements UserDao { @Autowired private JdbcTemplate jdbcTemplate; @Transactional public void create(String name, int age) { jdbcTemplate.update("insert into user(name, age) values (?, ?)", name, age); } public User query(int id) { List<User> user = jdbcTemplate.query("select * from user where id=" + id, new UserMapper()); return user.get(0); } @Transactional public void create2User() { create("b", 1); create("b", 1); } private static ApplicationContext context; public static void main(String[] args) { String xmlpath = "spring.xml"; context = new ClassPathXmlApplicationContext(xmlpath); UserDao userDao = (UserDao) context.getBean("userDaoImpl"); userDao.create("a", 1); userDao.create2User(); } }
执行结果
可以看到,在同一个事务中依次插入两条相同记录,都没有插入成功。