目录
编写Spring配置类 -- spring-context.xml
手动开启事务 -- connector
添加依赖
<dependencies>
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.10</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.27</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
封装工具类 -- DBUtils
package com.qfedu.tx.utils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**
* @Author XY
* @Date 2022/6/8 22:26
*/
public class DBUtils {
private static final Properties PROPERTIES = new Properties();
private static final ThreadLocal<Connection> THREAD_LOCAL = new ThreadLocal<>();
private static DataSource ds;
static {
try {
InputStream is = DBUtils.class.getResourceAsStream("/db.properties");
PROPERTIES.load(is);
ds = DruidDataSourceFactory.createDataSource(PROPERTIES);
} catch (Exception e) {
e.printStackTrace();
}
}
public static DataSource getDs() {
return ds;
}
public static Connection getConnection() {
Connection connection = THREAD_LOCAL.get();
if (connection == null) {
try {
Connection con = getDs().getConnection();
THREAD_LOCAL.set(con);
return con;
} catch (SQLException e) {
e.printStackTrace();
}
}
return connection;
}
public static void close(ResultSet resultSet, Statement statement, Connection connection) {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
编写操作类 -- AccountDao
package com.qfedu.tx.dao;
import com.qfedu.tx.utils.DBUtils;
import org.apache.commons.dbutils.QueryRunner;
import java.sql.SQLException;
/**
* @Author XY
* @Date 2022/6/8 22:42
*/
public class AccountDao {
QueryRunner queryRunner = new QueryRunner(DBUtils.getDs());
public Integer minusMoney(String username, Integer money) throws SQLException {
return queryRunner.update(DBUtils.getConnection(), "update account set balance = balance-? where username=?", money, username);
}
public Integer addMoney(String username, Integer money) throws SQLException {
return queryRunner.update(DBUtils.getConnection(), "update account set balance = balance+? where username=?", money, username);
}
}
编写服务类 -- AccountService
package com.qfedu.tx.service;
import com.qfedu.tx.dao.AccountDao;
import com.qfedu.tx.utils.DBUtils;
import java.sql.Connection;
import java.sql.SQLException;
/**
* @Author XY
* @Date 2022/6/8 22:45
*/
public class AccountService {
AccountDao accountDao = new AccountDao();
public String transfer(String from, String to, Integer money) {
Connection connection = DBUtils.getConnection();
try {
//关闭事务自动提交
connection.setAutoCommit(false);
Integer r1 = accountDao.minusMoney(from, money);
Integer r2 = accountDao.addMoney(to, money);
//提交事务
connection.commit();
if (r1 == 1 && r2 == 1) {
return "转账成功";
} else {
return "转账失败";
}
} catch (SQLException e) {
e.printStackTrace();
try {
//事务回滚
connection.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
}
return "转账失败,事务已回滚";
}
}
在转账的时候,也就是minusMoney()与addMoney()之间可以人为的添加一个异常(int i=1/0;) ,这样就可以在测试的时候,查看是否回滚。
编写配置类 -- db.properties
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test01
username=root
password=1234
在这个配置文件中可以修改相关配置,这样就可以实现跨平台
编写测试类
public class AccountServiceTest {
AccountService accountService = new AccountService();
@Test
public void transfer() {
String transfer = accountService.transfer("zhangsan", "lisi", 50);
System.out.println("transfer = " + transfer);
}
}
使用 transactionTemplate
编写操作类 -- AccountDao
package com.qfedu.tx.dao;
import org.springframework.jdbc.core.JdbcTemplate;
/**
* @Author XY
* @Date 2022/6/8 23:09
*/
public class AccountDao {
JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public Integer minusMoney(String username, Integer money) {
return jdbcTemplate.update("update account set balance = balance-? where username=?;", money, username);
}
public Integer addMoney(String username, Integer money) {
return jdbcTemplate.update("update account set balance = balance+? where username=?;", money, username);
}
}
编写服务类 -- AccountService
package com.qfedu.tx.service;
import com.qfedu.tx.dao.AccountDao;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
/**
* @Author XY
* @Date 2022/6/8 23:11
*/
public class AccountService {
AccountDao accountDao;
TransactionTemplate transactionTemplate;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
public void transfer(String from, String to, Integer money) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
accountDao.minusMoney(from, money);
accountDao.addMoney(to, money);
}
});
}
}
在转账的时候,也就是minusMoney()与addMoney()之间可以人为的添加一个异常(int i=1/0;) ,这样就可以在测试的时候,查看是否回滚。
编写Spring配置类 -- spring-context.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 class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
<property name="url" value="jdbc:mysql:///test01?serverTimezone=Asia/Shanghai"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</bean>
<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean class="com.qfedu.tx.dao.AccountDao" id="accountDao">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean class="com.qfedu.tx.service.AccountService" id="accountService">
<property name="accountDao" ref="accountDao"/>
<property name="transactionTemplate" ref="transactionTemplate"/>
</bean>
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean class="org.springframework.transaction.support.TransactionTemplate" id="transactionTemplate">
<property name="transactionManager" ref="transactionManager"/>
</bean>
</beans>
编写测试类
package com.qfedu.tx.service;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @Author waowang
* @Date 2022/6/8 23:14
*/
public class AccountServiceTest {
private static ClassPathXmlApplicationContext ctx;
@Test
public void transfer() {
AccountService accountService = ctx.getBean(AccountService.class);
accountService.transfer("zhangsan", "lisi", 50);
}
@Before
public void setUp() throws Exception {
ctx = new ClassPathXmlApplicationContext("spring-context.xml");
}
@After
public void tearDown() throws Exception {
ctx.close();
}
}
使用注解 -- @transactional
编写操作类 -- AccountDao
package com.qfedu.tx.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
/**
* @Author XY
* @Date 2022/6/8 23:09
*/
@Repository
public class AccountDao {
@Autowired
JdbcTemplate jdbcTemplate;
public Integer minusMoney(String username, Integer money) {
return jdbcTemplate.update("update account set balance = balance-? where username=?;", money, username);
}
public Integer addMoney(String username, Integer money) {
return jdbcTemplate.update("update account set balance = balance+? where username=?;", money, username);
}
}
编写服务类 -- AccountService
package com.qfedu.tx.service;
import com.qfedu.tx.dao.AccountDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.Transactional;
/**
* @Author XY
* @Date 2022/6/9 15:20
*/
@Service
@EnableTransactionManagement
public class AccountService {
@Autowired
AccountDao accountDao;
@Transactional
public void transfer(String from, String to, Integer money) {
accountDao.minusMoney(from, money);
accountDao.addMoney(to, money);
}
}
在转账的时候,也就是minusMoney()与addMoney()之间可以人为的添加一个异常(int i=1/0;) ,这样就可以在测试的时候,查看是否回滚。
编写配置文件 -- JavaConfig
使用 transactionTemplate 的时候,我是用 xml 文件配置的,下面我用 Java 代码配置
package com.qfedu.tx.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
/**
* @Author XY
* @Date 2022/6/9 15:39
*/
@Configuration
@ComponentScan("com.qfedu.tx")
public class JavaConfig {
@Bean
DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test01?serverTimezone?Asia/Shanghai");
dataSource.setUsername("root");
dataSource.setPassword("1234");
return dataSource;
}
@Bean
DataSourceTransactionManager sourceTransactionManager() {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource());
return transactionManager;
}
@Bean
JdbcTemplate jdbcTemplate() {
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource());
return jdbcTemplate;
}
}
编写测试类
package com.qfedu.tx.service;
import com.qfedu.tx.config.JavaConfig;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @Author XY
* @Date 2022/6/9 15:25
*/
public class AccountServiceTest {
@Test
public void test01() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(JavaConfig.class);
AccountService accountService = ctx.getBean(AccountService.class);
accountService.transfer("zhangsan", "lisi", 50);
ctx.close();
}
}