1.service注入dao,在dao中注入JDBCTemplate,在JDBCTemplate中注入DataSource
整体架构
UserDao文件
package com.atguigu.spring5.dao;
/**
* @author
* @create 2022-03-02 15:06
*/
public interface UserDao {
}
UserDaoImpl文件
package com.atguigu.spring5.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
/**
* @author
* @create 2022-03-02 15:06
*/
@Repository
public class UserDaoImpl implements UserDao{
@Autowired
private JdbcTemplate jdbcTemplate;
}
UserService文件
package com.atguigu.spring5.service;
import com.atguigu.spring5.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author
* @create 2022-03-02 15:06
*/
@Service
public class UserService {
@Autowired
private UserDao userDao;
}
spring.xml文件
<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:aop="http://www.springframework.org/schema/aop"
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/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">
<context:component-scan base-package="com.atguigu">context:component-scan>
<context:property-placeholder location="classpath:druid.properties">context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="url" value="${jdbc.url}">property>
<property name="username" value="${jdbc.username}">property>
<property name="password" value="${jdbc.password}">property>
<property name="driverClassName" value="${jdbc.driverclass}">property>
bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource">property>
bean>
beans>
druit.properties配置文件
jdbc.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT
jdbc.driverclass=com.mysql.cj.jdbc.Driver
jdbc.username=root
jdbc.password=abc123
UserDao.java 文件
package com.atguigu.spring5.dao;
/**
* @author huxuyang
* @create 2022-03-02 15:06
*/
public interface UserDao {
void addMoney();
void reduceMoney();
}
UserDaoImpl.java 文件
package com.atguigu.spring5.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
/**
* @author huxuyang
* @create 2022-03-02 15:06
*/
@Repository
public class UserDaoImpl implements UserDao{
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void addMoney() {
String sql = "update t_account set money = money- ? where username= ?";
jdbcTemplate.update(sql, 100, "zhangsan");
}
@Override
public void reduceMoney() {
String sql = "update t_account set money = money + ? where username= ?";
jdbcTemplate.update(sql, 100, "lisi");
}
}
UserService.java文件
package com.atguigu.spring5.service;
import com.atguigu.spring5.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author huxuyang
* @create 2022-03-02 15:06
*/
@Service
public class UserService {
// 注入dao
@Autowired
private UserDao userDao;
// 转账的过程
public void accountMoney(){
// 1.先给张三减100
userDao.reduceMoney();
// 2.再给李四增100
userDao.addMoney();
}
}
package com.atguigu.spring5.test;
import com.atguigu.spring5.service.UserService;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.sql.DataSource;
import java.sql.Connection;
/**
* @author huxuyang
* @create 2022-03-02 15:09
*/
public class test {
@Test //测试数据库连接
public void testJDBC() throws Exception{
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
DataSource dataSource = context.getBean("dataSource", DataSource.class);
Connection connection = dataSource.getConnection();
System.out.println(connection);
}
@Test // 测试转账操作
public void testAccount() throws Exception{
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = context.getBean("userService", UserService.class);
userService.accountMoney();
}
}
模拟错误过程
// 转账的过程
public void accountMoney(){
// 1.先给张三减100
userDao.reduceMoney();
// 模拟错误
int a = 1/0;
// 2.再给李四增100
userDao.addMoney();
}
// 转账的过程
public void accountMoney(){
try {
// 第一步 开启事务
// 第二步 进行业务操作
// 1.先给张三减100
userDao.reduceMoney();
// 模拟错误
int a = 1/0;
// 2.再给李四增100
userDao.addMoney();
// 第三步 如果没有发生异常,则提交事务
} catch (Exception e) {
// 第四步 如果发生异常,则将事务回滚
}
}
事务一般添加到service层
(1)基于注解方式实现(常用)
(2)基于xml配置文件方式实现
Spring中提供一个接口PlatformTransactionManager,此接口代表事务管理器,这个接口针对不同的框架提供不同的实现类。
针对JDBCTemplate和Mybatis框架的实现类是DataSourceTransactionManager
针对Hibernate的框架的实现类是HibernateTransactionManager
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource">property>
bean>
- 2.1 在spirng配置文件中先引入名称空间tx
<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:aop="http://www.springframework.org/schema/aop"
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/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">
<tx:annotation-driven transaction-manager="transactionManager">tx:annotation-driven>
- 3.1 @Transactional ,这个注解可以添加到类上面,也可以添加到方法上面
- 3.2如果这个注解添加到类上面,这个类里面所有的方法都添加了事务
- 3.3 如果把这个注解添加到方法上面,那么只为这个方法添加事务
配置完成后,spring.xml配置文件如下
<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:aop="http://www.springframework.org/schema/aop"
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/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">
<context:component-scan base-package="com.atguigu">context:component-scan>
<context:property-placeholder location="classpath:druid.properties">context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="url" value="${jdbc.url}">property>
<property name="username" value="${jdbc.username}">property>
<property name="password" value="${jdbc.password}">property>
<property name="driverClassName" value="${jdbc.driverclass}">property>
bean>
<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">property>
bean>
<tx:annotation-driven transaction-manager="transactionManager">tx:annotation-driven>
beans>
servic层文件如下
@Service
@Transactional
public class UserService {
// .............
}
package com.atguigu.spring5.service;
import com.atguigu.spring5.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Transactional;
/**
* @author huxuyang
* @create 2022-03-02 15:06
*/
@Service
@Transactional
public class UserService {
// 注入dao
@Autowired
private UserDao userDao;
// 转账的过程
public void accountMoney() {
// 1.先给张三减100
userDao.reduceMoney();
// 模拟错误
int a = 1 / 0;
// 2.再给李四增100
userDao.addMoney();
}
}
测试代码
@Test // 测试转账操作
public void testAccount() throws Exception{
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = context.getBean("userService", UserService.class);
userService.accountMoney();
}
测试前数据库状态
测试后数据库状态
多个事务之间进行调用,在调用的过程中事务是如果进行管理的
默认的传播行为是required
@Service
@Transactional(propagation = Propagation.REQUIRED)
MySQL默认隔离级别为REPEATABLE_READ
@Service
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
@Service
@Transactional(
propagation = Propagation.REQUIRED,
isolation = Isolation.REPEATABLE_READ,
timeout = -1,
readOnly = false,
rollbackFor = {NoClassDefFoundError.class}
)
完整架构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kKsvUDWg-1646224431965)(Spring%E4%B8%AD%E4%BA%8B%E5%8A%A1%E7%9A%84%E4%BD%BF%E7%94%A8.assets/image-20220302194530271-16462215330491.png)]
package com.atguigu.spring5.dao;
/**
* @author huxuyang
* @create 2022-03-02 15:06
*/
public interface UserDao {
void addMoney();
void reduceMoney();
}
package com.atguigu.spring5.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
/**
* @author huxuyang
* @create 2022-03-02 15:06
*/
@Repository
public class UserDaoImpl implements UserDao{
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void addMoney() {
String sql = "update t_account set money = money- ? where username= ?";
jdbcTemplate.update(sql, 100, "zhangsan");
}
@Override
public void reduceMoney() {
String sql = "update t_account set money = money + ? where username= ?";
jdbcTemplate.update(sql, 100, "lisi");
}
}
package com.atguigu.spring5.service;
import com.atguigu.spring5.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
/**
* @author huxuyang
* @create 2022-03-02 15:06
*/
@Service
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ, timeout = -1,readOnly = false,rollbackFor = {NoClassDefFoundError.class})
public class UserService {
// 注入dao
@Autowired
private UserDao userDao;
// 转账的过程
public void accountMoney() {
// 1.先给张三减100
userDao.reduceMoney();
// 模拟错误
int a = 1 / 0;
// 2.再给李四增100
userDao.addMoney();
}
}
jdbc.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT
jdbc.driverclass=com.mysql.cj.jdbc.Driver
jdbc.username=root
jdbc.password=abc123
<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:aop="http://www.springframework.org/schema/aop"
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/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">
<context:component-scan base-package="com.atguigu">context:component-scan>
<context:property-placeholder location="classpath:druid.properties">context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="url" value="${jdbc.url}">property>
<property name="username" value="${jdbc.username}">property>
<property name="password" value="${jdbc.password}">property>
<property name="driverClassName" value="${jdbc.driverclass}">property>
bean>
<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">property>
bean>
<tx:annotation-driven transaction-manager="transactionManager">tx:annotation-driven>
beans>
package com.atguigu.spring5.test;
import com.atguigu.spring5.service.UserService;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.sql.DataSource;
import java.sql.Connection;
/**
* @author huxuyang
* @create 2022-03-02 15:09
*/
public class test {
@Test //测试数据库连接
public void testJDBC() throws Exception{
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
DataSource dataSource = context.getBean("dataSource", DataSource.class);
Connection connection = dataSource.getConnection();
System.out.println(connection);
}
@Test // 测试转账操作
public void testAccount() throws Exception{
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = context.getBean("userService", UserService.class);
userService.accountMoney();
}
}
第一步 配置事务管理器
第二步 配置通知
第三步 配置切入点和切面
<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:aop="http://www.springframework.org/schema/aop"
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/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">
<context:component-scan base-package="com.atguigu">context:component-scan>
<context:property-placeholder location="classpath:druid.properties">context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="url" value="${jdbc.url}">property>
<property name="username" value="${jdbc.username}">property>
<property name="password" value="${jdbc.password}">property>
<property name="driverClassName" value="${jdbc.driverclass}">property>
bean>
<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">property>
bean>
<tx:advice id="txadvice">
<tx:attributes>
<tx:method name="accountMoney" propagation="REQUIRED" isolation="READ_COMMITTED"/>
tx:attributes>
tx:advice>
<aop:config>
<aop:pointcut id="pt" expression="(execution(* com.atguigu.spring5.service.UserService.*(..)))"/>
<aop:advisor advice-ref="txadvice" pointcut-ref="pt">aop:advisor>
aop:config>
beans>
package com.atguigu.spring5.service;
import com.atguigu.spring5.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author huxuyang
* @create 2022-03-02 15:06
*/
@Service
public class UserService {
// 注入dao
@Autowired
private UserDao userDao;
// 转账的过程
public void accountMoney() {
// 1.先给张三减100
userDao.reduceMoney();
// 模拟错误
int a = 1 / 0;
// 2.再给李四增100
userDao.addMoney();
}
}
package com.atguigu.spring5.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.junit.Test;
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 org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import javax.xml.crypto.Data;
import java.io.InputStream;
import java.util.Properties;
/**
* @author huxuyang
* @create 2022-03-02 20:04
*/
@Configuration //配置类
@ComponentScan(basePackages = "com.atguigu") // 组件扫描
@EnableTransactionManagement // 开启事务
public class TxConfig {
// 创建数据库连接池
@Bean
public DruidDataSource getDruidDataSource() throws Exception{
DruidDataSource dataSource = new DruidDataSource();
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties");
Properties pros = new Properties();
pros.load(is);
dataSource.setDriverClassName(pros.getProperty("jdbc.driverclass"));
dataSource.setUrl(pros.getProperty("jdbc.url"));
dataSource.setUsername(pros.getProperty("jdbc.username"));
dataSource.setPassword(pros.getProperty("jdbc.password"));
return dataSource;
}
// 创建JDBCTemplate对象
@Bean
public JdbcTemplate getJdbcTemplate(DataSource dataSource){
JdbcTemplate jdbcTemplate = new JdbcTemplate();
// 参数中有dataSource,创建bean时会到ioc容器中根据类型找到dataSource并注入
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
// 创建事务管理器
@Bean
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}
UserService 文件
package com.atguigu.spring5.service;
import com.atguigu.spring5.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author huxuyang
* @create 2022-03-02 15:06
*/
@Service
public class UserService {
// 注入dao
@Autowired
private UserDao userDao;
// 转账的过程
public void accountMoney() {
// 1.先给张三减100
userDao.reduceMoney();
// 模拟错误
int a = 1 / 0;
// 2.再给李四增100
userDao.addMoney();
}
}
@Test // 测试转账操作
public void testAccount2() throws Exception{
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TxConfig.class);
UserService userService = context.getBean("userService", UserService.class);
userService.accountMoney();
}