什么是事务
在java应用中,事务就是把多个操作数据库单元捆绑在一起,看看做一个整体。处于逻辑单元中所有操作要么全部成功,要么全部失败!
比如: 在银行转账业务中,A用户向B用户转钱,扣A用户金额,其次B用户加上指定金额。转账就是一个完整的事务,如果执行sql操作失败,事务回滚到开启之前状态。
事务的四大特性-----ACID原则
事务是数据库操作的基本单位,具有四个核心特性(ACID),确保数据操作的可靠性和一致性:
原子性(Atomicity)
事务被视为不可分割的最小单元,要么全部执行成功,要么全部失败回滚。例如,转账操作中扣款和收款必须同时成功或同时撤销。
一致性(Consistency)
事务执行前后,数据库必须从一个一致状态转移到另一个一致状态。例如,转账前后账户总金额应保持不变。
隔离性(Isolation)
多个事务并发执行时,一个事务的操作不应影响其他事务。数据库通过锁机制或MVCC(多版本并发控制)实现隔离级别(如读未提交、读已提交、可重复读、串行化)。
持久性(Durability)
事务一旦提交,其对数据的修改将永久保存在数据库中,即使系统崩溃也不会丢失。通常通过预写日志(WAL)技术实现。
实际应用示例
在银行系统中,ACID特性确保转账操作的安全:原子性避免部分操作失败导致数据不一致;隔离性防止并发转账时的数据冲突;持久性保证转账记录永久保存。
Mysql事务
在MySQL中,默认情况下每条SQL语句都作为一个独立的事务执行。如需手动控制事务管理,需要遵循以下操作流程:
- 开启事务:
sql
START TRANSACTION;
-
执行事务中的SQL操作
-
提交事务:
sql
COMMIT;
- 回滚事务(如需要):
sql
ROLLBACK;
SQL案例
sql
#模拟赚钱
start transaction;
# 修改指定用户金额
update t_user set money=money - 1000 where username='ykj';
update t_user set money=money + 1000 where usernam='root';
#提交事务
commit
#回滚事务
rollback;
JDBC事务管理
在jdbc中,默认情况下,发送一条sql语句就是一个事务,如果需要手动控制或者管理事务,则需要通过Connection 对象进行操作。
并且一个事务中多条sql数据必须使用同一个Connection对象,否则事务失效。
通过Connection对象中 setAutoCommit(booean flag); 默认情况下flag参数值为true,表示一条sql就是一个事务。如果需要手动控制事务则,必须设置改方法的参数为false。
commit()方法:表示提交事务
rollback():回滚事务
JDBC中如何管理事务:
java
//1.获取Connection对象
try{
//2.开启事务
//3.执行事务中 逻辑单元(多条sql语句)
//4.提交事务
}catch(Exception e){
//捕获异常
//5.回滚事务
}finally{
//关闭资源
}
案例
核心配置文件开启扫描包即可
1.添加依赖
java
<!-- 导入mysql驱动包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
2.编写接口和实现类
UserService接口:
java
public interface UserService {
//用户转账方法
void transactionAccount(String fromName,String toName,double money) throws SQLException;
}
UserServiceImpl实现类
java
@Service
public class UserServiceImpl implements UserService {
/**
* 用户转账的方法
* @param fromName 用户名1
* @param toName 用户名2
* @param money 转账金额
*/
@Override
public void transactionAccount(String fromName, String toName, double money) throws SQLException {
//1.获取连接对象
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/class118?serverTimezone=GMT",
"root", "123456");
try{
//2.开启事务
con.setAutoCommit(false);
//3.执行事务业务逻辑 (转账逻辑)
String sql = "update t_user set money = money + ? where username = ?";
//4.获取预处理对象
PreparedStatement ps = con.prepareStatement(sql);
//5.设置占位符参数
ps.setDouble(1, -money);
ps.setString(2, fromName);
//6.执行sql
ps.executeUpdate();
// int i = 10 / 0;
//第2条sql
String sql2 = "update t_user set money = money + ? where username = ?";
PreparedStatement ps2 = con.prepareStatement(sql2);
ps.setDouble(1, money);
ps.setString(2, toName);
ps.executeUpdate();
//提交事务
con.commit();
}catch (Exception e){
e.printStackTrace(); //打印异常信息
//回滚事务
con.rollback();
}
}
}
3.UserController类
java
@Controller
public class UserController {
@Autowired
private UserService userService;
/**
* 用户转账方法
*/
public void transactionAccount(String fromName, String toName, double money) throws SQLException {
userService.transactionAccount(fromName, toName, money);
}
}
4.测试类
java
public class UserControllerTest {
public static void main(String[] args) throws SQLException {
//1.加载spring核心配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.获取UserController对象
UserController userController = (UserController) context.getBean("userController");
//调用转账方法
userController.transactionAccount("zhangsan", "lisi", 1000);
}
}
Spring整合Mybatis框架
整合思路:
MyBatis 的核心组件(包括数据库连接池对象、SqlSessionFactory、SqlSession 以及 Mapper 代理对象)都需要交由 Spring 框架统一管理。
案例
创建数据库表
创建数据库表
sql
CREATE TABLE `t_product` (
`pid` int NOT NULL AUTO_INCREMENT,
`productName` varchar(255) DEFAULT NULL,
`price` double(10,2) DEFAULT NULL,
`stock` int DEFAULT NULL,
`description` varchar(255) DEFAULT NULL,
`createtime` datetime DEFAULT NULL,
`updatetime` datetime DEFAULT NULL,
PRIMARY KEY (`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=105 DEFAULT CHARSET=utf8;
创建Java项目,导入Spring和mybatis相关依赖
XML
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<!-- 定义依赖的版本号 -->
<spring.version>6.0.6</spring.version>
</properties>
<dependencies>
<!-- junit测试依赖-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- spring相关依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</dependency>
<!-- 导入dom4j相关依赖-->
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>3.0.0</version>
</dependency>
<!-- 导入mysql驱动包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<!-- mybatis相关依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.19</version>
</dependency>
<!-- 数据库连接池依赖 管理Connection对象-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.12</version>
</dependency>
<!-- 导入spring整合mybatis依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>3.0.4</version>
</dependency>
</dependencies>
创建mybatis核心配置文件
XML
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 扫描指定包下xml映射文件-->
<mappers>
<package name="com.wn.mapper"/>
</mappers>
</configuration>
创建jdbc.properties配置文件
XML
db.driverClassName=com.mysql.cj.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/class118?serverTimezone=GMT
db.username=root
db.password=123456
创建实体类
java
/**
* 商品类
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Product {
private Integer pid;
private String productName;
private Double price;
private Integer stock;
private String description;
private Date createtime;
private Date updatetime;
}
7、创建Mapper接口
java
/**
* 商品 mapper层接口
*/
public interface ProductMapper {
/**
* 查询所有商品信息
*/
@Select("select * from t_product")
List<Product> findAll();
}
8、创建sevice层接口和实现类
ProductService接口:
java
public interface ProductService {
List<Product> findAll();
}
ProductServiceImpl实现类:
java
/**
* 商品业务层实现类
*/
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
private ProductMapper productMapper;
/**
* 查询所有商品信息
*/
@Override
public List<Product> findAll() {
return productMapper.findAll();
}
}
9、创建Controller层类
java
/**
* 商品 控制层类
*/
@Controller
public class ProductController {
@Autowired
private ProductService productService;
/**
* 查询所有商品信息
*/
public List<Product> findAll() {
return productService.findAll();
}
}
10、创建Spring核心配置文件
XML
<beans xmlns="http://www.springframework.org/schema/beans"
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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd" >
<!-- 1.扫描指定包下及其子包下的spring注解-->
<context:component-scan base-package="com.wn" />
<!-- 2.加载db.properties配置文件-->
<context:property-placeholder location="classpath:mybatis/db.properties" />
<!-- 3.配置数据库连接池对象和参数 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!-- 3.1、配置数据库连接池连接参数-->
<property name="driverClassName" value="${db.driverClassName}"></property>
<property name="url" value="${db.url}"></property>
<property name="username" value="${db.username}"></property>
<property name="password" value="${db.password}"></property>
</bean>
<!-- 4.配置SqlSessionFactory对象和参数-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 4.1指定加载mybatis核心配置文件-->
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml"></property>
<!-- 4。2、指定数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 5.扫描执行包下所有mapper接口,由spring容器管理代理对象 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 5.1、执行扫描mapper接口包-->
<property name="basePackage" value="com.wn.mapper"></property>
<!-- 指定sqlSessionfactory-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
</beans>
11、测试类
java
public class UserControllerTest {
public static void main(String[] args) throws SQLException {
//1.加载spring核心配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.获取UserController对象
UserController userController = (UserController) context.getBean("userController");
//3.调用方法
// Map<String,Object> map = userController.queryByEmail("5664332222@qq.com");
// System.out.println(map);
//调用转账方法
userController.transactionAccount("张三", "李四", 1000);
}
}