编程式事务管理方法允许你在源代码编程的方式下管理事务。虽然带来了极大地灵活性,但是它很难维护。

实践前提:

1、在MySql新建Student,Marks两张表,脚本如下:



CREATE TABLE Student(
ID INT NOT NULL AUTO_INCREMENT,
NAME VARCHAR(20) NOT NULL,
AGE INT NOT NULL,
PRIMARY KEY (ID)
);



CREATE TABLE Marks(
SID INT NOT NULL,
MARKS INT NOT NULL,
YEAR INT NOT NULL
);


2、增加mysql-connector-java.jar包,POM配置如下:



<!-- mysql-connector-java -->
<!-- http://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>


3、原理:

使用PlatformTransactionManager来实现编程式方法实现事务。要开始一个新事务,需要有一个带有适当的transaction属性的TransactionDefinition的实例。这里,我们使用默认的transaction属性创建DefaultTransactionDefinition的一个实例。当TransactionDefinition创建后,可以通过调用getTransaction()方法来开始事务,该方法会返回TransactionStatus的一个实例。TransactionStatus对象帮助追踪当前的事务状态,并且最终,如果一切运行顺利,你可以使用PlatformTransactionManager的commit()方法来提交这个事务,否则的话,你可以使用rollback()方法来回滚整个操作。

例子:

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.jsoft.testspring</groupId>
<artifactId>testtx</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>testtx</name>
<url>http://maven.apache.org</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>

<!-- Spring Core -->
<!-- http://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>

<!-- Spring Context -->
<!-- http://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>

<!-- Spring JDBC -->
<!-- http://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>

<!-- Spring Transaction -->
<!-- http://mvnrepository.com/artifact/org.springframework/spring-tx -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>

<!-- mysql-connector-java -->
<!-- http://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>

</dependencies>
</project>


StudentMarks.java:



package com.jsoft.testspring.testtx;

public class StudentMarks {
private Integer age;
private String name;
private Integer id;

private Integer marks;
private Integer year;
private Integer sid;

public void setAge(Integer age) {
this.age = age;
}

public Integer getAge() {
return age;
}

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

public String getName() {
return name;
}

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

public Integer getId() {
return id;
}


public void setMarks(Integer marks) {
this.marks = marks;
}

public Integer getMarks() {
return marks;
}

public void setYear(Integer year) {
this.year = year;
}

public Integer getYear() {
return year;
}

public void setSid(Integer sid) {
this.sid = sid;
}

public Integer getSid() {
return sid;
}
}


StudentMarksMapper.java:



package com.jsoft.testspring.testtx;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.springframework.jdbc.core.RowMapper;

public class StudentMarksMapper implements RowMapper<StudentMarks> {

@Override
public StudentMarks mapRow(ResultSet rs, int arg1) throws SQLException {
// TODO Auto-generated method stub
StudentMarks student = new StudentMarks();
student.setId(rs.getInt("id"));
student.setName(rs.getString("name"));
student.setAge(rs.getInt("age"));

student.setSid(rs.getInt("sid"));
student.setMarks(rs.getInt("marks"));
student.setYear(rs.getInt("year"));

return student;
}

}


StudentDAO.java:



package com.jsoft.testspring.testtx;

import java.util.List;

import javax.sql.DataSource;

import org.springframework.transaction.PlatformTransactionManager;

public interface StudentDAO {

public void setDataSource(DataSource ds);

public void setTransactionManager(PlatformTransactionManager transactionManager);

public void create(String name, Integer age, Integer marks, Integer year);

public StudentMarks getStudent(Integer id);

public List<StudentMarks> listStudents();

public void delete(Integer id);

public void update(Integer id, String name, Integer age, Integer marks, Integer year);
}


StudentJDBCTemplate.java:



package com.jsoft.testspring.testtx;

import java.util.List;

import javax.sql.DataSource;

import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

public class StudentJDBCTemplate implements StudentDAO {

private DataSource dataSource;
private JdbcTemplate jdbcTemplateObject;

private PlatformTransactionManager transactionManager;

@Override
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
this.jdbcTemplateObject = new JdbcTemplate(dataSource);
}

@Override
public void setTransactionManager(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}

@Override
public void create(String name, Integer age, Integer marks, Integer year) {
TransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(def);
try {
String SQL1 = "insert into Student (name, age) values (?, ?)";
jdbcTemplateObject.update( SQL1, name, age);
String SQL2 = "select max(id) from Student";
int sid = jdbcTemplateObject.queryForInt( SQL2 );
String SQL3 = "insert into Marks(sid, marks, year) values (?, ?, ?)";
jdbcTemplateObject.update( SQL3, sid, marks, year);
System.out.println("Created Name = " + name + ", Age = " + age);
transactionManager.commit(status);
} catch (DataAccessException e) {
System.out.println("Error in creating record, rolling back");
transactionManager.rollback(status);
throw e;
}
return;
}

@Override
public StudentMarks getStudent(Integer id) {
String SQL = "select * from Student,Marks where id = ? and Student.id=Marks.sid";
StudentMarks student = jdbcTemplateObject.queryForObject(SQL, new Object[] { id }, new StudentMarksMapper());
return student;
}

@Override
public List<StudentMarks> listStudents() {
String SQL = "select * from Student,Marks where Student.id = Marks.sid";
List<StudentMarks> students = jdbcTemplateObject.query(SQL, new StudentMarksMapper());
return students;
}

@Override
public void delete(Integer id) {
TransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(def);
try {
String SQL1 = "delete from Student where id = ?";
jdbcTemplateObject.update(SQL1, id);
System.out.println("Deleted Record with ID = " + id);
String SQL2 = "delete from Marks where sid = ?";
jdbcTemplateObject.update(SQL2, id);
System.out.println("Deleted Record with SID = " + id);
transactionManager.commit(status);
} catch (DataAccessException e) {
System.out.println("Error in creating record, rolling back");
transactionManager.rollback(status);
throw e;
}
return;
}

@Override
public void update(Integer id, String name, Integer age, Integer marks, Integer year) {
TransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(def);
try {
String SQL1 = "update Student set age = ?,name = ? where id = ?";
jdbcTemplateObject.update(SQL1, age,name, id);
System.out.println("Updated Record with ID = " + id);
String SQL2 = "update Marks set marks = ?,year = ? where sid = ?";
jdbcTemplateObject.update(SQL2, marks,year, id);
System.out.println("Updated Record with SID = " + id);
transactionManager.commit(status);
} catch (DataAccessException e) {
System.out.println("Error in creating record, rolling back");
transactionManager.rollback(status);
throw e;
}
return;
}

}


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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">

<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/test?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>

<!-- Definition for studentJDBCTemplate bean -->
<bean id="studentJDBCTemplate" class="com.jsoft.testspring.testtx.StudentJDBCTemplate">
<property name="dataSource" ref="dataSource" />
<property name="transactionManager" ref="transactionManager" />
</bean>

</beans>


测试结果:

Spring编程式事务管理_sql