当前位置: 首页 > news >正文

Spring框架(三)

目录

一、JDBC模板技术概述

1.1 什么是JDBC模板

二、JdbcTemplate使用实战

2.1 基础使用(手动创建对象)

2.2 使用Spring管理模板类

2.3 使用开源连接池(Druid)

三、模拟转账开发

3.1 基础实现

3.1.1 Service层

3.1.2 Dao层

3.1.3 配置文件

3.1.4 测试代码

3.2 使用JdbcDaoSupport实现

3.2.1 DAO层改进

3.2.2 配置文件

3.2.3 测试代码

四、Spring框架的事务管理

4.1 事务管理相关API

4.1.1 PlatformTransactionManager接口

4.1.2 TransactionDefinition接口

4.2 声明式事务管理

4.2.1 配置文件方式

4.2.2 配置文件+注解方式

4.2.3 纯注解方式

4.3 转账案例与事务管理

4.3.1 Service层

4.3.2 Dao层

4.3.3 测试代码

4.4 事务传播行为

4.5 事务隔离级别

总结


一、JDBC模板技术概述

1.1 什么是JDBC模板

Spring框架提供的JdbcTemplate类简化了传统JDBC开发流程,解决了以下痛点:

  • 自动管理连接资源(Connection/Statement/ResultSet)

  • 自动处理JDBC异常(将Checked异常转换为RuntimeException)

  • 提供简洁的API执行SQL语句

  • 支持事务管理

二、JdbcTemplate使用实战

2.1 基础使用(手动创建对象)

1. 环境搭建(创建 maven 工程,引入坐标依赖

<?xml version="1.0" encoding="UTF-8"?>
<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.qcby</groupId><artifactId>springAOP03</artifactId><version>1.0-SNAPSHOT</version><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.2.RELEASE</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.12</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.0.2.RELEASE</version></dependency><dependency><groupId>aopalliance</groupId><artifactId>aopalliance</artifactId><version>1.0</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.0.2.RELEASE</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.13</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.25</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.0.2.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>5.0.2.RELEASE</version></dependency><!-- 三、Druid开源的连接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.10</version></dependency></dependencies></project>

2. 测试代码

package com.qcby.demo1;import org.junit.Test;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;import java.util.List;
import java.util.Map;public class Demo1 {/*** 一、使用 new 对象方式完成*/@Testpublic void run1(){// 创建连接池对象,Spring 框架内置了连接池对象DriverManagerDataSource dataSource = new DriverManagerDataSource();// 设置 4 个参数dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");dataSource.setUrl("jdbc:mysql:///spring_db");dataSource.setUsername("root");dataSource.setPassword("12345");try {// 提供模板,创建对象JdbcTemplate template = new JdbcTemplate(dataSource);// 完成数据的增删改查//1.新增
//            template.update("insert into account values (null,?,?)","耶耶 ",1000);
//            System.out.println("添加成功!");//2.删除
//            template.update("delete from account where name = ? ","耶耶");
//            System.out.println("删除成功!");//3.更新
//            template.update("update account set money=money-? where name = ? ",100.00,"可可");
//            System.out.println("更新成功!");//4.查询List<Map<String, Object>> accounts=template.queryForList("select * from account");//遍历结果集System.out.println("\n当前账户信息:");for (Map<String, Object> account:accounts){System.out.println("ID:"+ account.get("id") +";姓名:" + account.get("name") +";余额:" + account.get("money"));}}catch (Exception e){System.out.println("操作失败!!!");e.printStackTrace();}}}

2.2 使用Spring管理模板类

1. 将数据源和模板类交给Spring容器管理

<?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:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 使用Spring框架管理 --><!-- 二、Spring管理内置的连接池 demo1_1.java测试--><!-- 配置连接池 --><bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql:///spring_db" /><property name="username" value="root" /><property name="password" value="12345" /></bean><!--配置 jdbc 模板 --><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource" /></bean> </beans>

2. 测试代码

package com.qcby.demo1;import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import java.util.List;
import java.util.Map;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = "classpath:applicationContext_jdbc.xml")
public class Demo1_1 {@Autowiredprivate JdbcTemplate jdbcTemplate;/*** 测试的方式*/@Testpublic void run1(){try {jdbcTemplate.update("insert into account values (null,?,?)","图图",500);System.out.println("添加成功!");}catch (Exception e){e.printStackTrace();}}@Testpublic void run2(){try {jdbcTemplate.update("delete from account where name = ? ","图图");System.out.println("删除成功!");}catch (Exception e){e.printStackTrace();}}@Testpublic void run3(){try {jdbcTemplate.update("update account set money=money-? where name = ? ",100.00,"可可");System.out.println("更新成功!");}catch (Exception e){e.printStackTrace();}}@Testpublic void run4(){try {List<Map<String, Object>> accounts=jdbcTemplate.queryForList("select * from account");//遍历结果集System.out.println("\n当前账户信息:");for (Map<String, Object> account:accounts){System.out.println("ID:"+ account.get("id") +";姓名:" + account.get("name") +";余额:" + account.get("money"));}}catch (Exception e){e.printStackTrace();}}}

2.3 使用开源连接池(Druid)

1. 添加Druid依赖

<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.10</version>
</dependency>

2. 创建jdbc.properties

jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql:///spring_db
jdbc.username=root
jdbc.password=12345

3. Spring配置

<?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:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 三、Spring 框架管理开源的连接池  属性文件:jdbc.properties--><!-- 第一种写法 --><!-- 使用开源连接池<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql:///spring_db" /><property name="username" value="root" /><property name="password" value="12345" /></bean>--><!-- 加载属性文件<bean id="placeholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><property name="location" value="classpath:jdbc.properties" /></bean>--><!-- 第二种写法:使用提供标签的方式 --><!-- 引入属性文件 --><context:property-placeholder location="classpath:jdbc.properties" /><!-- 加载属性的文件 配置Druid数据源 --><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${jdbc.driverClassName}" /><property name="url" value="${jdbc.url}" /><property name="username" value="${jdbc.username}" /><property name="password" value="${jdbc.password}" /></bean><!-- 配置 jdbc 模板 --><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><!-- 注入属性,set方法 --><property name="dataSource" ref="dataSource" /></bean></beans>

4. 测试

package com.qcby.demo1;import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = "classpath:applicationContext_jdbc.xml")
public class Demo1_2 {@Autowiredprivate JdbcTemplate jdbcTemplate;/*** 测试的方式*/@Testpublic void run1(){jdbcTemplate.update("insert into account values (null,?,?)","熊四",800);System.out.println("新增成功!");}/*** 修改*/@Testpublic void run2(){jdbcTemplate.update("update account set name = ?,money = ? where id = ?","小凤",100,7);System.out.println("修改成功!");}/*** 删除*/@Testpublic void run3(){jdbcTemplate.update("delete from account where id = ?",9);System.out.println("删除成功!");}/*** 通过 id 查询*/@Testpublic void run4(){Account account = jdbcTemplate.queryForObject("select * from account where id = ?", new BeanMapper(), 6);System.out.println(account);}/*** 查询所有的数据*/@Testpublic void run5(){List<Account> list = jdbcTemplate.query("select * from account", new BeanMapper());for (Account account : list) {System.out.println(account);}}
}/*** 实现类,用来进行数据封装的*/
class BeanMapper implements RowMapper<Account> {/*** 是一行一行进行数据封装的* @param resultSet* @param i* @return* @throws SQLException*/public Account mapRow(ResultSet resultSet, int i) throws SQLException {Account account = new Account();account.setId(resultSet.getInt("id"));account.setName(resultSet.getString("name"));account.setMoney(resultSet.getDouble("money"));return account;}}

三、模拟转账开发

3.1 基础实现

3.1.1 Service层

package com.qcby.demo2.service;public interface AccountService {/*** 转账的方法* @param out 付款人* @param in 收款人* @param money 金额*/public void pay(String out,String in,double money);
}package com.qcby.demo2.service;import com.qcby.demo2.dao.AccountDao;public class AccountServiceImpl implements AccountService{private AccountDao accountDao;public void setAccountDao(AccountDao accountDao) {this.accountDao = accountDao;}/*** 转账方法* @param out 付款人* @param in 收款人* @param money 金额*/public void pay(String out, String in, double money) {// 调用 dao 方法accountDao.outMoney(out,money);accountDao.inMoney(in,money);}
}

3.1.2 Dao层

package com.qcby.demo2.dao;public interface AccountDao {/*** 付款* @param out* @param money*/public void outMoney(String out,double money);/*** 收款* @param in* @param money*/public void inMoney(String in,double money);}package com.qcby.demo2.dao;import org.springframework.jdbc.core.JdbcTemplate;public class AccountDaoImpl implements AccountDao{private JdbcTemplate jdbcTemplate;public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {this.jdbcTemplate = jdbcTemplate;}/*** 付款* @param out* @param money*/public void outMoney(String out, double money) {jdbcTemplate.update("update account set money = money - ? where name = ?",money,out);}/*** 收款* @param in* @param money*/public void inMoney(String in, double money) {jdbcTemplate.update("update account set money = money + ? where name = ?",money,in);}
}

3.1.3 配置文件

<?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:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!--第二种写法:使用提供标签的方式--><context:property-placeholder location="classpath:jdbc.properties" /><!--加载属性的文件--><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${jdbc.driverClassName}" /><property name="url" value="${jdbc.url}" /><property name="username" value="${jdbc.username}" /><property name="password" value="${jdbc.password}" /></bean><!--配置 Jdbc 模板类--><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource" /></bean><!--配置 service--><bean id="accountService" class="com.qcby.demo2.service.AccountServiceImpl"><property name="accountDao" ref="accountDao"/></bean><!--配置 service--><bean id="accountDao" class="com.qcby.demo2.dao.AccountDaoImpl"><property name="jdbcTemplate" ref="jdbcTemplate" /></bean></beans>

3.1.4 测试代码

package com.qcby.demo2;import com.qcby.demo2.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = "classpath:applicationContext_dao1.xml")
public class Demo2 {@Autowiredprivate AccountService accountService;/*** 测试转账的方法*/@Testpublic void testPay(){accountService.pay("熊大","熊二",100);}}

3.2 使用JdbcDaoSupport实现

3.2.1 DAO层改进

package com.qcby.demo2.dao;import org.springframework.jdbc.core.support.JdbcDaoSupport;//extends JdbcDaoSupport
public class AccountDaoImpl1 extends JdbcDaoSupport implements AccountDao{/*** 付款* @param out* @param money*/public void outMoney(String out, double money) {this.getJdbcTemplate().update("update account set money = money - ? where name = ?",money,out);}/*** 收款* @param in* @param money*/public void inMoney(String in, double money) {this.getJdbcTemplate().update("update account set money = money + ? where name = ?",money,in);}
}

3.2.2 配置文件

<?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:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!--第二种写法:使用提供标签的方式--><context:property-placeholder location="classpath:jdbc.properties" /><!--加载属性的文件--><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${jdbc.driverClassName}" /><property name="url" value="${jdbc.url}" /><property name="username" value="${jdbc.username}" /><property name="password" value="${jdbc.password}" /></bean><!--配置 Jdbc 模板类<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource" /></bean>--><!--配置 service--><bean id="accountService" class="com.qcby.demo2.service.AccountServiceImpl"><property name="accountDao" ref="accountDao"/></bean><!--配置 dao<bean id="accountDao" class="com.qcby.demo2.dao.AccountDaoImpl"><property name="jdbcTemplate" ref="jdbcTemplate" /></bean>--><!-- 在accountDaoImpl中extends JdbcDaoSupport --><bean id="accountDao" class="com.qcby.demo2.dao.AccountDaoImpl1"><property name="dataSource" ref="dataSource"/></bean></beans>

3.2.3 测试代码

package com.qcby.demo2;import com.qcby.demo2.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = "classpath:applicationContext_dao2.xml")
public class Demo2_1 {@Autowiredprivate AccountService accountService;/*** 测试转账的方法*/@Testpublic void testPay(){accountService.pay("熊大","熊二",100);}
}

四、Spring框架的事务管理

4.1 事务管理相关API

4.1.1 PlatformTransactionManager接口

这是Spring事务管理的核心接口,根据不同的持久层框架有不同的实现:

  • DataSourceTransactionManager:用于JDBC

  • HibernateTransactionManager:用于Hibernate

  • JpaTransactionManager:用于JPA

4.1.2 TransactionDefinition接口

定义事务属性:

  • 事务隔离级别

  • 事务传播行为

  • 事务超时时间

  • 是否只读事务

4.2 声明式事务管理

4.2.1 配置文件方式

<!-- applicationContext_1.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"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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsd"><!--第二种写法:使用提供标签的方式--><context:property-placeholder location="classpath:jdbc.properties" /><!--加载属性的文件--><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${jdbc.driverClassName}" /><property name="url" value="${jdbc.url}" /><property name="username" value="${jdbc.username}" /><property name="password" value="${jdbc.password}" /></bean><!--配置平台事务管理器--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource" /></bean><!--配置事务的通知(没有自己编写切面类,通知方法也不是自己编写,Spring框架提供的)--><tx:advice id="txAdvice" transaction-manager="transactionManager"><tx:attributes><!--对 pay 进行增强,设置隔离级别,传播行为,超时的时间--><tx:method name="pay" isolation="DEFAULT" propagation="REQUIRED" /><tx:method name="find*" read-only="true" /></tx:attributes></tx:advice><!-- 配置 AOP 的增强 --><aop:config><!-- Spring 框架提供系统通知,使用 advisor 标签 --><aop:advisor advice-ref="txAdvice" pointcut="execution(public * com.qcby.demo3.AccountServiceImpl.pay(..))" /></aop:config><!-- 配置 service --><bean id="accountService" class="com.qcby.demo3.AccountServiceImpl"><property name="accountDao" ref="accountDao"/></bean><!-- 配置 dao --><bean id="accountDao" class="com.qcby.demo3.AccountDaoImpl"><property name="dataSource" ref="dataSource" /></bean></beans>

4.2.2 配置文件+注解方式

<?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:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsd"><!--开启注解的扫描--><context:component-scan base-package="com.qcby.demo3" /><!--第二种写法:使用提供标签的方式--><context:property-placeholder location="classpath:jdbc.properties" /><!--加载属性的文件--><bean id="dataSource"class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName"value="${jdbc.driverClassName}" /><property name="url" value="${jdbc.url}" /><property name="username" value="${jdbc.username}" /><property name="password" value="${jdbc.password}" /></bean><!--配置平台事务管理器--><bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource" /></bean><!--配置 Jdbc 模板类--><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource" /></bean><!--开启事务注解的支持--><tx:annotation-driven transaction-manager="transactionManager" /></beans>
package com.qcby.demo3;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;@Service
@Transactional(isolation = Isolation.DEFAULT)
public class AccountServiceImpl implements AccountService{@Autowiredprivate AccountDao accountDao;/*** 转账方法* @param out 付款人* @param in 收款人* @param money 金额*/public void pay(String out, String in, double money) {// 调用 dao 方法accountDao.outMoney(out,money);// int a = 10 / 0;accountDao.inMoney(in,money);// 模拟在转账过程中发生异常//int a = 10 / 0;}
}

4.2.3 纯注解方式

package com.qcby.demo3;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.jdbc.datasource.DriverManagerDataSource;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;import javax.annotation.Resource;
import javax.sql.DataSource;/*** 配置类* @author Administrator*/
@Configuration
@ComponentScan(basePackages="com.qcby.demo3")
@EnableTransactionManagement // 开启事务注解
public class SpringConfig {/*** @return* @throws Exception*/@Bean(name="dataSource")public DataSource createDataSource() throws Exception{// 创建连接池对象,Spring 框架内置了连接池对象DriverManagerDataSource dataSource = new DriverManagerDataSource();// 设置 4 个参数dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");dataSource.setUrl("jdbc:mysql:///spring_db");dataSource.setUsername("root");dataSource.setPassword("12345");return dataSource;}/*** 创建模板对象* @return*/@Resource(name="dataSource") // 不仅可以作用在属性上,也可以作用方法上。@Bean(name="jdbcTemplate") // 把 JdbcTemplate 保存到 IOC容器中public JdbcTemplate createJdbcTemplate(DataSource dataSource){JdbcTemplate template = new JdbcTemplate(dataSource);return template;}/*** 创建平台事务管理器对象* @param dataSource* @return*/@Resource(name="dataSource")@Bean(name="transactionManager")public PlatformTransactionManagercreateTransactionManager(DataSource dataSource){DataSourceTransactionManager manager = new DataSourceTransactionManager(dataSource);return manager;}}

4.3 转账案例与事务管理

4.3.1 Service层

package com.qcby.demo3;public interface AccountService {public void pay(String out, String in, double money);
}package com.qcby.demo3;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;@Service
@Transactional(isolation = Isolation.DEFAULT)
public class AccountServiceImpl implements AccountService{@Autowiredprivate AccountDao accountDao;/*** 转账方法* @param out 付款人* @param in 收款人* @param money 金额*/public void pay(String out, String in, double money) {// 调用 dao 方法accountDao.outMoney(out,money);// int a = 10 / 0;accountDao.inMoney(in,money);// 模拟在转账过程中发生异常//int a = 10 / 0;}
}

4.3.2 Dao层

package com.qcby.demo3;public interface AccountDao {/*** 付款* @param out* @param money*/public void outMoney(String out, double money);/*** 收款* @param in* @param money*/public void inMoney(String in, double money);}package com.qcby.demo3;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;@Repository
public class AccountDaoImpl implements AccountDao {@Autowiredprivate JdbcTemplate jdbcTemplate;/*** 付款* @param out* @param money*/public void outMoney(String out, double money) {jdbcTemplate.update("update account set money = money - ? where name = ?",money,out);}/*** 收款* @param in* @param money*/public void inMoney(String in, double money) {jdbcTemplate.update("update account set money = money + ? where name = ?",money,in);}
}

4.3.3 测试代码

package com.qcby.demo3;import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;// 1.配置文件+注解方式
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = "classpath:applicationContext_2.xml")// 2.纯注解方式
//@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(classes = SpringConfig.class)public class Demo3 {@Autowiredprivate com.qcby.demo3.AccountService accountService;/*** 测试转账的方法*/@Testpublic void testPay() {try {accountService.pay("熊大", "熊二", 100);System.out.println("转账成功!!!");} catch (Exception e) {e.printStackTrace();System.out.println("转账失败,事务已回滚!");}}
}

4.4 事务传播行为

Spring定义了7种事务传播行为:

  1. ​PROPAGATION_REQUIRED​​(默认):如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。

  2. ​PROPAGATION_SUPPORTS​​:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。

  3. ​PROPAGATION_MANDATORY​​:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。

  4. ​PROPAGATION_REQUIRES_NEW​​:创建一个新的事务,如果当前存在事务,则把当前事务挂起。

  5. ​PROPAGATION_NOT_SUPPORTED​​:以非事务方式运行,如果当前存在事务,则把当前事务挂起。

  6. ​PROPAGATION_NEVER​​:以非事务方式运行,如果当前存在事务,则抛出异常。

  7. ​PROPAGATION_NESTED​​:如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则创建一个新的事务。

4.5 事务隔离级别

Spring支持以下隔离级别:

  1. ​ISOLATION_DEFAULT​​:使用底层数据库的默认隔离级别。

  2. ​ISOLATION_READ_UNCOMMITTED​​:允许读取未提交的数据变更,可能导致脏读、幻读或不可重复读。

  3. ​ISOLATION_READ_COMMITTED​​:只能读取已提交的数据,防止脏读,但可能发生幻读和不可重复读。

  4. ​ISOLATION_REPEATABLE_READ​​:对同一字段的多次读取结果都是一致的,除非数据被当前事务修改,防止脏读和不可重复读,但可能发生幻读。

  5. ​ISOLATION_SERIALIZABLE​​:最高的隔离级别,完全服从ACID的隔离级别,确保事务串行执行,防止脏读、不可重复读和幻读。

总结

        本文详细介绍了Spring框架中JDBC模板技术的使用方法,Spring的JDBC模板技术大大简化了数据库操作代码,使开发者能够更专注于业务逻辑而非底层数据库交互细节。声明式事务管理则提供了灵活的事务控制方式,确保数据的一致性和完整性。

        在实际开发中,建议优先使用注解方式配置事务,它更简洁直观。对于复杂的事务需求,可以结合使用@Transactional的各种属性进行精细化控制。同时,合理选择事务隔离级别和传播行为,可以在保证数据安全的前提下提高系统性能。

相关文章:

  • 1688代采系统商品采集下单支付解决方案|官方API接口接入指南
  • npm cross-env工具包介绍(跨平台环境变量设置工具)
  • 机器学习第十五讲:决策树全面讲解:像玩“20个问题“游戏猜身份[特殊字符]
  • 国产linux系统(银河麒麟,统信uos)使用 PageOffice自定义Word模版中的数据区域
  • PyTorch深度学习框架60天进阶学习计划-第56天:大模型微调实践(二)
  • 【学习心得】Jupyter 如何在conda的base环境中其他虚拟环境内核
  • 动态IP赋能业务增效:技术解构与实战应用指南
  • Oracle数据库如何进行冷备份和恢复
  • 临床决策支持系统的提示工程优化路径深度解析
  • 使用IDEA开发Spark Maven应用程序【超详细教程】
  • Android framework 中间件开发(三)
  • docker(四)使用篇二:docker 镜像
  • unity之导入本地packages包
  • 若依框架SpringBoot从Mysql替换集成人大金仓(KingBase)数据库
  • Android 中 权限分类及申请方式
  • nlf loss 学习笔记
  • 智能呼入:云蝠大模型赋能政府热线
  • 激活函数全解析:定义、分类与 17 种常用函数详解
  • 编译opencv4.11gstreamer 参考
  • Spring Batch学习,和Spring Cloud Stream区别
  • 信俗与共:清代新疆回疆儒释道庙宇的中华政教
  • 幼儿园教师拍打孩子额头,新疆库尔勒教育局:涉事教师已被辞退
  • 外交部部长助理兼礼宾司司长洪磊接受美国新任驻华大使递交国书副本
  • 美国务卿鲁比奥抵达会场,将参加俄乌会谈
  • 全国省市县国土空间总体规划已基本批复完成,进入全面实施阶段
  • 中国结算澄清“严查场外配资”传闻:账户核查为多年惯例,无特殊安排