Spring框架的JDBC模板技术和事务管理

SpringJDBC

  • JDBC模板技术概述
  • JDBC的模板类的使用
  • Spring框架的事务管理
    • 配置文件方式
    • 半注解的方式
    • 纯注解的方式

JDBC模板技术概述

什么是 JDBC 模板技术?
JDBC 模板技术是 Spring 框架为简化持久层(数据库操作)编程而提供的一种封装机制,核心类为JdbcTemplate。它基于模板设计模式,将 JDBC 操作中重复、繁琐的底层代码进行封装,让开发者只需关注核心业务逻辑(如 SQL 语句编写、结果集处理)。

模板(template)技术的设计思想:
Spring 框架中提供了一系列以XxxTemplate命名的模板类(如JdbcTemplate、HibernateTemplate、RedisTemplate等),其核心思想是:将固定流程的代码封装为模板,将可变的业务逻辑通过回调接口暴露给开发者。

对于 JDBC 操作而言,固定流程包括:获取数据库连接(Connection)、创建 SQL 执行对象(Statement/PreparedStatement)、执行 SQL 语句、处理异常(如SQLException)、释放资源(关闭ResultSet、Statement、Connection)
JdbcTemplate将这些固定流程封装,开发者只需提供 SQL 语句和结果处理逻辑即可。

JDBC的模板类的使用

创建 maven java 工程,引入坐标依赖

    <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>5.1.6</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></dependencies>

new 对象的方式

编写测试代码

import org.junit.Test;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;public class Demo {/*** 使用的是 Spring 框架内置的连接池* 使用 new 对象方式完成*/@Testpublic void run1(){// 创建连接池对象,Spring 框架内置了连接池对象DriverManagerDataSource dataSource = new DriverManagerDataSource();// 设置 4 个参数dataSource.setDriverClassName("com.mysql.jdbc.Driver");dataSource.setUrl("jdbc:mysql:///ssm");dataSource.setUsername("root");dataSource.setPassword("root");// 提供模板,创建对象JdbcTemplate template = new JdbcTemplate(dataSource);// 完成数据的增删改查template.update("insert into account values (null,?,?)","熊大 ",1000);}
}

在这里插入图片描述

使用 Spring 框架管理模板类

applicationContext_jdbc.xml

    <!--配置连接池--><bean id="dataSource"class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql:///ssm" /><property name="username" value="root" /><property name="password" value="root" /></bean><!--配置 jdbc 模板--><bean id="jdbcTemplate"class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource" /></bean>
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;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = "classpath:applicationContext_jdbc.xml")
public class Demo1 {@Autowiredprivate JdbcTemplate jdbcTemplate;/*** 测试的方式* 使用开源连接池*/@Testpublic void run1(){jdbcTemplate.update("insert into account values (null,?,?)"," 小丽",500);}
}

在这里插入图片描述

Spring 框架管理开源的连接池

配置开源的连接池,使用 Druid 开源的连接池,引入坐标依赖

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

将数据库连接的信息配置到属性文件中

在这里插入图片描述

配置数据库访问相关的组件

    <!--加载属性文件--><bean id="placeholderConfigurer"class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><!-- 指定属性文件路径:classpath表示从类路径下查找 --><property name="location" value="classpath:jdbc.properties" /></bean><!--加载属性文件第二种写法:使用提供标签的方式--><!--<context:property-placeholderlocation="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>
  • 加载外部属性文件(数据库配置信息)
    <bean id="placeholderConfigurer"> 定义了PropertyPlaceholderConfigurer组件,作用是加载类路径(classpath)下的jdbc.properties属性文件,通过这种方式,数据库连接信息可以写在外部的jdbc.properties文件中,而非硬编码在 XML 里,便于后期修改和维护。<context:property-placeholder> 是另一种更简洁的加载属性文件的方式,功能完全一致。
  • 配置数据库连接池(Druid)
    <bean id="dataSource"> 定义了阿里巴巴的DruidDataSource(德鲁伊连接池),其中的driverClassName、url、username、password属性值使用 ${key} 格式的占位符,这些占位符会被前面加载的jdbc.properties文件中对应的键值对替换,通过配置连接池,应用可以高效地管理数据库连接,避免频繁创建 / 关闭连接的性能损耗。
  • 配置 Spring JDBC 模板
    <bean id="jdbcTemplate"> 定义了 Spring 提供的JdbcTemplate组件,这是一个简化 JDBC 操作的模板类,通过dataSource属性引用了前面定义的dataSource(数据库连接池),从而关联到数据库。

通过这段配置,Spring 容器会自动读取外部 jdbc.properties 中的数据库配置、初始化 Druid 连接池管理数据库连接、初始化 JdbcTemplate 并关联连接池。最终,应用可以直接从 Spring 容器中获取 jdbcTemplate 对象,便捷地进行数据库操作,同时数据库配置可通过修改 jdbc.properties 灵活调整,无需改动 XML 配置。

增删改查代码编写

import com.qcby.Model.Account;
import com.qcby.Model.BeanMapper;
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;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = "classpath:applicationContext_jdbc.xml")
public class Demo2 {@Autowiredprivate JdbcTemplate jdbcTemplate;/*** 测试的方式* 加载属性文件的方式*/@Testpublic void run1(){jdbcTemplate.update("insert into account values (null,?,?)"," 熊四",800);}/*** 修改*/@Testpublic void run2(){jdbcTemplate.update("update account set name = ?,money = ? where id = ?","光头强",100,7);}/*** 删除*/@Testpublic void run3(){jdbcTemplate.update("delete from account where id = ?",7);}/*** 通过 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);}}
}
public class Account {private int id;private String name;private double money;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getMoney() {return money;}public void setMoney(double money) {this.money = money;}@Overridepublic String toString() {return "Account{" +"id=" + id +", name='" + name + '\'' +", money=" + money +'}';}
}

Account类是account数据库表的映射实体类,属性对应数据表中的字段,作为数据载体,封装从数据库查询到的记录,或封装要插入或更新的数据。

import org.springframework.jdbc.core.RowMapper;import java.sql.ResultSet;
import java.sql.SQLException;/*** 实现类,用来进行数据封装的*/
public class BeanMapper implements RowMapper<Account>{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;}
}

BeanMapper 类是结果集映射器的实现类,它实现了Spring JDBC的 RowMapper 函数式接口并指定泛型为 Account,核心职责是将数据库查询返回的 ResultSet 结果集逐行转换为 Account 类型对象。
在这里插入图片描述

RowMapper 接口仅定义抽象方法 mapRow,BeanMapper 通过实现该方法定义具体行映射逻辑:当 JdbcTemplate 执行查询并遍历 ResultSet 时,每处理一行数据便调用 mapRow 方法,传入当前行 ResultSet 实例及行索引;mapRow 从结果集中提取对应字段值,赋值给新创建的 Account 对象并返回。
此实现解决了数据库结果集与Java对象的映射问题,使 JdbcTemplate 查询可直接返回 Account 对象或其集合,便于以面向对象方式处理查询结果。

实现效果:

在这里插入图片描述

使用JDBC模板操作数据库实现模拟转账开发

Service 层代码的编写

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

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);
}
import com.qcby.dao.AccountDao;
import org.springframework.jdbc.core.JdbcTemplate;public class AccountDaoImpl implements AccountDao{// 依赖Spring的JdbcTemplate,通过JdbcTemplate执行具体的SQL语句,操作数据库private JdbcTemplate jdbcTemplate;//提供setter方法,让Spring注入JdbcTemplatepublic 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);}
}

配置文件代码编写

    <!--加载jdbc.properties文件,使用提供标签的方式--><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模板类,创建JdbcTemplate对象,并注入dataSource--><bean id="jdbcTemplate"class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource" /></bean><!--配置Service对象,注入Dao--><bean id="accountDao" class="com.qcby.dao.impl.AccountDaoImpl"><property name="jdbcTemplate" ref="jdbcTemplate" /></bean><!--配置Dao对象,注入JdbcTemplate--><bean id="accountService" class="com.qcby.service.impl.AccountServiceImpl"><property name="accountDao" ref="accountDao"/></bean>

测试代码编写

import com.qcby.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 Demo3 {@Autowiredprivate AccountService accountService;/*** 测试转账的方法*/@Testpublic void testPay(){accountService.pay("熊大","熊二",100);}
}

Dao 层编写的第二种方式

import com.qcby.dao.AccountDao;
import org.springframework.jdbc.core.support.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);}
}

AccountDaoImpl1 继承了 Spring 提供的 JdbcDaoSupport 类,该类是 Spring 为简化 JDBC 操作提供的工具类,内部已封装了 JdbcTemplate 对象,子类可直接通过 getJdbcTemplate() 方法获取 JdbcTemplate,无需手动定义和注入,减少重复代码。

配置文件编写

    <!--第二种写法:使用提供标签的方式--><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><!--配置 service--><bean id="accountServicePx"class="com.qcby.service.impl.AccountServiceImpl"><property name="accountDao" ref="accountDao"/></bean><bean id="accountDao" class="com.qcby.dao.impl.AccountDaoImpl1"><property name="dataSource" ref="dataSource" /></bean>

编写测试类

import com.qcby.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 Demo4 {@Autowiredprivate AccountService accountService;/*** 测试转账的方法*/@Testpublic void testPay(){accountService.pay("熊大","熊二",100);}
}

Spring框架的事务管理

核心接口与实现类
平台事务管理器:PlatformTransactionManager
PlatformTransactionManager 是 Spring 事务管理的核心接口,定义了事务操作的标准规范,是事务执行器的角色。它屏蔽了不同持久层框架的事务差异,开发者需根据实际使用的持久层技术选择对应的实现类。Spring 为不同的持久层框架提供了对应的 PlatformTransactionManager 实现
如果使用的 Spring 的 JDBC 模板或者 MyBatis 框架,需要选择 DataSourceTransactionManager 实现类
如果使用的是 Hibernate 的框架,需要选择 HibernateTransactionManager 实现类

接口方法如下:
void commit(TransactionStatus status)
void rollback(TransactionStatus status)

事务规则定义:TransactionDefinition
TransactionDefinition 是事务规则描述的接口,定义了事务隔离级别、事务传播行为,这些属性决定了事务的运行规则。

配置文件方式

<?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-placeholderlocation="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.service.impl.AccountServiceImpl1.pay(..))" /></aop:config><!--配置 service--><bean id="accountServicePx"class="com.qcby.service.impl.AccountServiceImpl"><property name="accountDao" ref="accountDao"/></bean><!--配置 dao --><bean id="accountDao" class="com.qcby.dao.impl.AccountDaoImpl1"><property name="dataSource" ref="dataSource" /></bean>
</beans>

这段 XML 配置文件是Spring 框架基于 XML 实现声明式事务管理的核心配置,同时整合了数据库连接、数据访问层、业务逻辑层的 Bean 定义,最终实现对AccountServiceImpl类中pay方法的事务增强。
tx:advice 是 Spring 提供的事务通知组件,无需手动编写切面类和通知方法,是事务规则的载体,transaction-manager=“transactionManager” 关联配置的事务管理器,通知需通过管理器执行事务操作,tx:attributes 定义哪些方法需要事务及事务的具体规则。

aop:advisor 是 Spring 的通知器,专门用于绑定事务通知(tx:advice)和切入点,区别于普通 AOP 的 aop:aspect,advisor 是 Spring 为事务等系统级通知提供的简化标签。advice-ref=“txAdvice” 关联定义的事务通知,pointcut=“execution(…)” 定义切入点。

测试

import com.qcby.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_tx.xml")
public class Demo5 {@Autowiredprivate AccountService accountService;/*** 测试转账的方法*/@Testpublic void testPay(){accountService.pay("熊大","熊二",100);}
}

半注解的方式

<?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: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/txhttp://www.springframework.org/schema/tx/spring-tx.xsd"><!--开启注解的扫描--><context:component-scan base-package="com.qcby" /><!--第二种写法:使用提供标签的方式--><context:property-placeholderlocation="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>

Dao 层代码

@Repository("accountDao_1")
public class AccountDaoImpl_1 implements AccountDao {// 依赖Spring的JdbcTemplate,通过JdbcTemplate执行具体的SQL语句,操作数据库private JdbcTemplate jdbcTemplate;//提供setter方法,让Spring注入JdbcTemplate@Autowiredpublic 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);}
}

Service 层代码

import com.qcby.dao.AccountDao;
import com.qcby.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
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_1 implements AccountService{@Autowired@Qualifier("accountDao_1")private AccountDao accountDao;/*** 转账方法* @param out 付款人* @param in 收款人* @param money 金额*/public void pay(String out, String in, double money) {// 调用 dao 方法accountDao.outMoney(out,money);// 模拟异常//int a = 1/0;accountDao.inMoney(in,money);}
}

测试

import com.qcby.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_tx1.xml")
public class Demo6 {@Autowiredprivate AccountService accountService;/*** 测试转账的方法*/@Testpublic void testPay(){accountService.pay("熊大","熊二",100);}
}

纯注解的方式

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

@Configuration:标识当前类是一个 Spring 配置类,Spring 会扫描并解析其中的配置;
@ComponentScan(basePackages=“com.qcby”):开启组件扫描,扫描指定包及其子包下的类,被@Component等注解标记的类会被自动注册到 Spring 容器中;
@EnableTransactionManagement:半注解和纯注解形式需要开启 Spring 的注解式事务管理支持,与 XML 配置中的<tx:annotation-driven/> 作用相同;
创建并配置数据源DataSource,用于建立与数据库的连接;创建JdbcTemplate实例,并注册到 Spring 容器中,@Resource(name = “dataSource”) 用于指定注入名为 dataSource 的 Bean 到方法参数 dataSource 中,该注解不仅可以作用在属性上,也可以以作用方法上;创建平台事务管理器PlatformTransactionManager,是 Spring 事务管理的核心组件。使用DataSourceTransactionManager(基于数据源的事务管理器),同样依赖dataSource,因为事务需要绑定数据库连接。

测试

import com.qcby.config.SpringConfig;
import com.qcby.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(classes = SpringConfig.class)
public class Demo7 {// 注入要测试的Service@Autowiredprivate AccountService accountService;@Testpublic void testNormalPay() {accountService.pay("熊大", "熊二", 100);System.out.println("正常转账测试完成");}
}

在这里插入图片描述

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

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

相关文章

将文件部署到受管主机

目录 1.ansible.builtin中用于创建、更新或删除多行文本块的模块是什么 2.copy模块的作用 3.fetch模块的作用 4.file模块的作用 5.lineinfile模块的作用 6.stat模块的作用 7.要确保受管主机上存在文件&#xff0c;类似touch命令功能&#xff0c;还能设置权限等的模块及操作是怎…

Dell PowerEdge R620 服务器内存和硬盘罢工了

文章目录前言调查原因查找解决方案硬盘问题内存问题总结前言 月黑风高夜&#xff0c;服务宕机时。做服务端技术的&#xff0c;谁还没半夜遇到个服务挂掉的情况&#xff0c;而像我这种半兼职网管的工作&#xff0c;遇到机器问题的概率也就更大了&#xff0c;本来周五晚上写完总…

2025:SourceTree 启用/禁用Mercurial 或 Git,像素级细节

最近使用Git管理工具的时候&#xff0c;发现还是SourceTree好用些&#xff0c;但是使用SourceTree带来一个问题&#xff1a;就是每次在重新打开SourceTree的时候&#xff0c;都会重新下载Mercurial.zip文件&#xff0c;查了一下&#xff0c;一般情况下我们是不需要使用Mercuria…

安卓 Google Maps 的使用和开发步骤

文章目录1. main2. Android 谷歌地图3. 源码Reference1. main 在国内选择的SDK可以是高德、百度、腾讯、xxxx等&#xff0c;但在国外&#xff0c;你首选是谷歌&#xff0c;因此要进行Google地图的开发你首先要解决下面三个问题 VPN Google账号 信用卡American Express&#x…

Linux -- 应用层协议Http

1.HTTP背景知识 HTTP协议&#xff1a;HTTP&#xff08;HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff09;的本质是运行在 TCP/IP 协议族之上的 “应用层协议”&#xff0c;核心作用是定义客户端&#xff08;如浏览器、APP&#xff09;与服务器之间的 “数据…

R 语言本身并不直接支持 Python 中 f“{series_matrix}.txt“ 这样的字符串字面量格式化(f-string)语法 glue函数

R 语言本身并不直接支持 Python 中 f"{series_matrix}.txt" 这样的字符串字面量格式化&#xff08;f-string&#xff09;语法。 在 R 中&#xff0c;要实现字符串拼接或格式化&#xff0c;你需要使用其他方法。下表对比了 Python f-string 和 R 中常见对应方法的主要…

【AI智能体】亮数据MCP Server × Dify:AI智能体获取实时影音数据就是这么简单

文章目录一、引言&#xff1a;AI 应用与实时影音数据的融合价值1、传统采集方式的痛点2、MCP Server 的创新价值二、亮数据 MCP Server 概览1、什么是 MCP Server&#xff1f;2、支持的影音平台和API接口3、产品特色亮点三、业务场景示例设计1、选定场景&#xff1a;竞品分析与…

从《Attention Is All You Need》深入理解Transformer

2017年的《Attention Is All You Need》论文提出的Transformer架构&#xff0c;不仅彻底改变了自然语言处理的格局&#xff0c;更为现代人工智能的发展奠定了坚实基础。本文将带你深入解析这一划时代模型的核心思想、技术细节及其深远影响。&#x1f504; 一、背景与动机&#…

【08】AI辅助编程完整的安卓二次商业实战-修改消息聊天框背景色-触发聊天让程序异常终止bug牵涉更多聊天消息发送优化处理-优雅草卓伊凡

【08】AI辅助编程完整的安卓二次商业实战-修改消息聊天框背景色-触发聊天让程序异常终止bug牵涉更多聊天消息发送优化处理-优雅草卓伊凡引言本次二开布局没有变&#xff0c;但是下一次整体布局会有变&#xff0c;不过本次开发发现朋友圈跳转功能的流程步骤也做了一定的变化。原…

心理调适与情绪管理实训室:支撑康养旅游人才心理能力培养

在康养休闲旅游服务专业的教学体系中&#xff0c;心理调适与情绪管理实训室作为关键教学场所&#xff0c;承担着培养学生心理服务能力、情绪疏导技能和人际沟通素养的重要任务。随着社会对康养旅游服务质量要求的提升&#xff0c;具备心理调适与情绪管理能力的专业人才日益受到…

Oracle sql tuning guide 翻译 Part 6 --- 优化器控制

第五部分优化器控制你可以用提示信息和初始化参数来影响优化器的判断和运作方式。Influencing the Optimizer Optimizer defaults are adequate for most operations, but not all.In some cases you may have information unknown to the optimizer, or need to tune the opti…

pthread_mutex_lock函数深度解析

摘要 pthread_mutex_lock是POSIX线程库中用于实现线程同步的核心函数&#xff0c;它通过对互斥锁的加锁操作来确保多个线程对共享资源的安全访问。本文从互斥锁的历史背景和发展脉络入手&#xff0c;详细解析了pthread_mutex_lock函数的设计理念、实现机制和使用场景。通过生产…

qt QBoxSet详解

1、概述QBoxSet 类代表箱形图中的一个条目。箱形条目是范围和由五个不同值构成的三个中值的图形表示。这五个值分别是&#xff1a;下极值、下四分位数、中位数、上四分位数和上极值。QBoxSet 提供了多种方法来设置和获取这些值&#xff0c;并且可以与 QBoxPlotSeries 和 QChart…

机器学习势函数(MLPF)入门:用DeePMD-kit加速亿级原子模拟

点击 “AladdinEdu&#xff0c;同学们用得起的【H卡】算力平台”&#xff0c;注册即送-H卡级别算力&#xff0c;80G大显存&#xff0c;按量计费&#xff0c;灵活弹性&#xff0c;顶级配置&#xff0c;学生更享专属优惠。 引言&#xff1a;从传统分子模拟到机器学习势函数的革命…

制作uniapp需要的storyboard全屏ios启动图

//锁定竖屏 plus.screen.lockOrientation("portrait-primary") // #endif首先准备启动图两个dc_launchscreen_portrait_background2x.png(750*1624)dc_launchscreen_portrait_background3x.png(1125*2436)LaunchScreen.storyboard文件内容如下<?xml version"…

OpenCV:答题卡识别

目录 一、项目原理 二、环境准备 三、核心代码实现 1. 导入必要库 2. 定义关键函数 坐标点排序函数 透视变换函数 轮廓排序函数 图像显示函数 3. 主程序实现 图像预处理 轮廓检测与答题卡定位 透视变换矫正 答案识别与评分 四、实现效果 本文将介绍如何使用 Ope…

机器宠物(以四足宠物为主)四肢与关节的系统化设计指南

1. 目标与约束先行 目标&#xff1a;自然步态&#xff08;走/小跑/小跳&#xff09;、安全亲和、低噪、跌倒不致损&#xff1b;支持地毯/木地板/瓷砖等家庭地面。约束&#xff1a;体重 1–6 kg&#xff1b;单次续航 ≥ 30–60 min&#xff1b;整机成本与可维护性&#xff1b;室…

spark hive presto doris 对substr函数的差异

Spark、Hive、Presto&#xff08;现更名为 Trino&#xff09;和 Doris&#xff08;原百度 Palo&#xff09;的 substr 函数在功能上都是用于截取字符串的子串&#xff0c;但在起始索引规则和参数含义上存在差异&#xff0c;这是导致结果不同的主要原因。以下是它们的具体区别&a…

开题报告之基于AI Agent智能问答的旅游网站

课题题目&#xff1a; 基于AI Agent智能问答的旅游网站 学生姓名&#xff1a; 学 号&#xff1a; 学 院&#xff1a; 专业年级&#xff1a; 指导教师&#xff1a; 开题报告word版&#xff1a; 开题报告word版 一、课题的研究目的和意义&#xff08;本…

HTB打靶复个小盘

文章目录jerrySauGoodGamesdevvotexpaper最近打了不少靶场&#xff0c;虽然难度都不算高&#xff0c;但也学到不少东西&#xff0c;中间去打了一周的实网渗透&#xff0c;打完后联系了一家企业准备面试&#xff0c;感觉面试准备的差不多了&#xff0c;回来继续打靶&#xff0c;…