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的各种属性进行精细化控制。同时,合理选择事务隔离级别和传播行为,可以在保证数据安全的前提下提高系统性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/news/905871.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[计算机网络]网络层

文章目录 408考研大纲IPV4数据报格式协议: IPv4 地址DHCP协议IP组播 408考研大纲 IPV4数据报格式 协议: 1:ICMP 6:TCP 17:UDP IPv4 地址 特殊IP 网络号全1又称直接广播地址&#xff0c;32位全1又称受限广播地址 因为255.255.255.255只能在本网络内广播&#xff0c;路由器不…

影楼精修-肤色统一算法解析

注意&#xff1a;本文样例图片为了避免侵权&#xff0c;均使用AIGC生成&#xff1b; 本文介绍影楼精修中肤色统一算法的实现方案&#xff0c;并以像素蛋糕为例&#xff0c;进行分析说明。 肤色统一就是将人像照片中皮肤区域的颜色进行统一&#xff0c;看起来颜色均匀一致&…

计算机网络:什么是计算机网络?它的定义和组成是什么?

计算机网络是指通过通信设备和传输介质&#xff0c;将分布在不同地理位置的计算机、终端设备及其他网络设备连接起来&#xff0c;实现资源共享、数据传输和协同工作的系统。其核心目标是使设备之间能够高效、可靠地交换信息。 关键组成部分 硬件设备 终端设备&#xff1a;如计算…

深度学习---获取模型中间层输出的意义

一、什么是 Hook&#xff08;钩子函数&#xff09;&#xff1f; 在 PyTorch 中&#xff0c;Hook 是一种机制&#xff0c;允许我们在模型的前向传播或反向传播过程中&#xff0c;插入自定义的函数&#xff0c;用来观察或修改中间数据。 最常用的 hook 是 forward hook&#xf…

存储器上如何存储1和0

在计算机存储器中&#xff0c;数据最终以**二进制形式&#xff08;0和1&#xff09;**存储&#xff0c;这是由硬件特性和电子电路的物理特性决定的。以下是具体存储方式的详细解析&#xff1a; 一、存储的物理基础&#xff1a;半导体电路与电平信号 计算机存储器&#xff08;…

Qt中的RCC

Qt资源系统(Qt resource system)是一种独立于平台的机制&#xff0c;用于在应用程序中传输资源文件。如果你的应用程序始终需要一组特定的文件(例如图标、翻译文件和图片)&#xff0c;并且你不想使用特定于系统的方式来打包和定位这些资源&#xff0c;则可以使用Qt资源系统。 最…

2918. 数组的最小相等和

2918. 数组的最小相等和 题目链接&#xff1a;2918. 数组的最小相等和 代码如下&#xff1a; class Solution { public:long long minSum(vector<int>& nums1, vector<int>& nums2) {auto [sum1, zero1] calc(nums1);auto [sum2, zero2] calc(nums2);i…

使用 Docker 部署 OnlyOffice

使用 Docker 部署 OnlyOffice 在如今容器化技术盛行的时代&#xff0c;Docker 已成为应用快速部署和隔离的最佳选择。OnlyOffice 作为一款功能强大的在线办公套件&#xff0c;通过 Docker 部署不仅能够简化安装和维护流程&#xff0c;还能在不同环境中保持一致性&#xff0c;极…

DDD领域驱动介绍

&#x1f4d5;我是廖志伟&#xff0c;一名Java开发工程师、《Java项目实战——深入理解大型互联网企业通用技术》&#xff08;基础篇&#xff09;、&#xff08;进阶篇&#xff09;、&#xff08;架构篇&#xff09;清华大学出版社签约作家、Java领域优质创作者、CSDN博客专家、…

前端 CSS 样式书写与选择器 基础知识

1.CSS介绍 CSS是Cascading Style Sheet的缩写&#xff0c;中文意思为"层叠样式表"&#xff0c;它是网页的装饰者&#xff0c;用来修饰各标签 排版(大小、边距、背景、位置等)、改变字体的样式(字体大小、字体颜色、对齐方式等)。 2.CSS书写位置 2.1 样式表特征 层…

鸿蒙 从打开一个新窗口到Stage模型的UIAbility组件

打开一个新的窗口 我们首先来实现如何在一个应用中打开一个新窗口&#xff0c;使用的模型是 Stage 模型 在项目文件里&#xff0c;新建一个 newWindow.ets 新文件 src/main/ets/pages/newWindow.ets newWindow.ets文件里面随便写点什么都行&#xff0c;这里是第一步创建的文件…

Linux的日志管理

日志管理服务rsyslogd 配置文件 | 日志类型 | 说明 | | -------------------- | ----------------------------------- | | auth | pam产生的日志 | | authpriv | ssh、ftp等…

【PhysUnits】4.1 类型级比特位实现解释(boolean.rs)

一、源码 该代码实现了一个类型级(type-level)的布尔系统&#xff0c;允许在编译时进行布尔运算。 //! 类型级比特位实现 //! //! 这些是基础的比特位类型&#xff0c;作为本库中其他数值类型的构建基础 //! //! 已实现的**类型运算符**&#xff1a; //! //! - 来自 core::op…

【docker】--数据卷挂载

文章目录 存储卷管理创建存储卷查看存储卷详细信息查看存储卷删除存储卷 存储卷管理 # 目录挂载 docker run -v 本机目录&#xff1a;容器目录#1&#xff09; # 将容器内部的 “/usr/share/nginx/html” 进行持久化挂载 会在宿主机生成一个随机的存储卷 docker run -v /usr/sh…

双重差分模型学习笔记2(理论)

【DID最全总结】90分钟带你速通双重差分&#xff01;_哔哩哔哩_bilibili 目录 一、staggered DID 交错双重差分 二、动态双重差分 动态双重差分法公式解释 符号解释 公式逻辑与案例 与标准DID的区别 总结 “双减” 政策动态差分模型 &#xff08;一&#xff09;设定处…

预测模型开发与评估:基于机器学习的数据分析实践

在当今数据驱动的时代&#xff0c;预测模型已成为各行各业决策制定的核心工具。本文将分享我在COMP5310课程项目中开发预测模型的经验&#xff0c;探讨从数据清洗到模型优化的完整过程&#xff0c;并提供详细的技术实现代码。 ## 研究问题与数据集 ### 研究问题 我们的研究聚焦…

Java 并发编程归纳总结(可重入锁 | JMM | synchronized 实现原理)

1、锁的可重入 一个不可重入的锁&#xff0c;抢占该锁的方法递归调用自己&#xff0c;或者两个持有该锁的方法之间发生调用&#xff0c;都会发生死锁。以之前实现的显式独占锁为例&#xff0c;在递归调用时会发生死锁&#xff1a; public class MyLock implements Lock {/* 仅…

数据治理域——数据同步设计

摘要 本文主要介绍了数据同步的多种方式&#xff0c;包括直连同步、数据文件同步和数据库日志解析同步。每种方式都有其适用场景、技术特点、优缺点以及适用的数据类型和实时性要求。文章还详细探讨了数据直连同步的特点、工作原理、优点、缺点、适用场景等&#xff0c;并对数…

AI人工智能在教育领域的应用

AI人工智能在教育领域的应用 随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;逐渐成为推动教育变革的重要力量。AI在教育领域的应用不仅改变了传统的教学模式&#xff0c;还为个性化学习、教育资源优化和教育管理带来了前所未有的机遇。本文将从多个方面探…

ohttps开启群晖ssl证书自动更新

开启群晖ssl证书自动更新OHTTPS ohttps是一个免费自动签发ssl证书、管理、部署的项目。 https://ohttps.com 本文举例以ohttps项目自动部署、更新群晖的ssl证书。 部署 签发证书 打开ohttps-证书管理-创建证书-按你实际情况创建证书。创建部署节点 打开Ohttps-部署节点-添加…