Spring集成的jdbc编码和事务管理
2010-06-25 12:01
661 查看
PersonServiceBean.java
Java代码
package cn.itcast.service.impl;
import java.util.List;
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Transactional;
import cn.itcast.bean.Person;
import cn.itcast.service.PersonService;
//@Transactional
public class PersonServiceBean implements PersonService {
//private DataSource dataSource;
/*
接下来就可以通过dataSource进行操作,但是我们不会直接面对dataSource进行操作,也建议大家不要面对
他进行操作,我们应该采用Spring为我们提供的JdbcTemplate这个辅助类来对JDBC进行操作,
因为这个类给我们封装了比较多的JDBC操作代码,我们只要调用它的方法就可以实现某些业务逻辑了
因为我们目前是通过jdbcTemplate这个类来对JDBC进行操作,所以数据源dataSource没必要再对它进行保存,
所以comment了dataSource的定义
*/
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
//把数据源dataSource作为构造器参数传进去
}
public void delete(Integer personid) {
jdbcTemplate.update("delete from person where id=?", new Object[]{personid},
new int[]{java.sql.Types.INTEGER});
}
public Person getPerson(Integer personid) {
return (Person)jdbcTemplate.queryForObject("select * from person where id=?", new Object[]{personid},
new int[]{java.sql.Types.INTEGER}, new PersonRowMapper());
/*
第三个参数代表:当查询到这条记录的时候,它会调用第三个对象的一个回调方法,只要实现了这个回调方法,那么就会调用
*/
}
@SuppressWarnings("unchecked")
public List<Person> getPersons() {
return (List<Person>)jdbcTemplate.query("select * from person", new PersonRowMapper());
}
public void save(Person person) {
jdbcTemplate.update("insert into person(name) values(?)", new Object[]{person.getName()},
new int[]{java.sql.Types.VARCHAR});
}
public void update(Person person) {
jdbcTemplate.update("update person set name=? where id=?", new Object[]{person.getName(), person.getId()},
new int[]{java.sql.Types.VARCHAR, java.sql.Types.INTEGER});
}
}
PersonRowMapper.java
Java代码
package cn.itcast.service.impl;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.jdbc.core.RowMapper;
import cn.itcast.bean.Person;
public class PersonRowMapper implements RowMapper {
/*
有同学会问,rs这个记录集进来时为什么不next一下?
是因为外部调用这个方法时已经在外面做了一下这种操作:if(rs.next())
外面做了这个操作,里面就不用再做这种操作
*/
public Object mapRow(ResultSet rs, int index) throws SQLException {
Person person = new Person(rs.getString("name"));
person.setId(rs.getInt("id"));
return person;
}
}
建一个单元测试:PersonServiceTest.java
Java代码
package junit.test;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.itcast.bean.Person;
import cn.itcast.service.PersonService;
public class PersonServiceTest {
private static PersonService personService;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
try {
ApplicationContext cxt = new ClassPathXmlApplicationContext("beans.xml");
personService = (PersonService) cxt.getBean("personService");
} catch (RuntimeException e) {
e.printStackTrace();
}
}
@Test public void save(){
for(int i=0; i<5; i++)
personService.save(new Person("传智播客"+ i));
}
@Test public void getPerson(){
Person person = personService.getPerson(1);
System.out.println(person.getName());
}
@Test public void update(){
Person person = personService.getPerson(1);
person.setName("张xx");
personService.update(person);
}
@Test public void delete(){
personService.delete(1);
}
@Test public void getBeans(){
for(Person person : personService.getPersons()){
System.out.println(person.getName());
}
}
}
运行save这个单元测试,数据库表记录是:看图
运行getPerson这个单元测试,控制台输出:传智播客0运行update这个单元测试,数据库表记录是:看图
运行delete这个单元测试,数据库表记录是:看图
运行getBeans这个单元测试,控制台输出:
传智播客1
传智播客2
传智播客3
传智播客4
这些就是JDBC + Spring的操作,但是大家留意一下,我们这个bean目前并没有受Spring的事务管理,为什么呢?因为我们并没有为这个bean定义@Transactional这个注解。 如果我们不定义这个注解的情况下呢,
Java代码
public void delete(Integer personid) {
jdbcTemplate.update("delete from person where id=?", new Object[]{personid},
new int[]{java.sql.Types.INTEGER});
}
这些jdbc的语句,它的执行都会在各自的事务中执行,如果说delete这个方法有两条语句
public void delete(Integer personid) {
jdbcTemplate.update("delete from person where id=?", new Object[]{personid},
new int[]{java.sql.Types.INTEGER});
jdbcTemplate.update("delete from person where id=?", new Object[]{personid},
new int[]{java.sql.Types.INTEGER});
}
那么每条语句都会在各自的事务中执行,他们是无法保证在同一个事务中执行的,这时候会出现一些问题。
我们为了保证这两条语句在同一条事务中执行,我们应该使用容器给我们提供的申明事务@Transactional这个注解,申明了事务,那么默认它会使得delete这个方法需要事务,然后保证里面的操作在同一事务里执行,所以在业务bean PersonServiceBean上面别忘了加上@Transactional事务注解
PersonServiceBean.java
Java代码
@Transactional
public class PersonServiceBean implements PersonService {
........................
}
加上了这个注解后,就明确告诉Spring容器这个PersonServiceBean现在是要受Spring的事务管理的,这样bean底下所有的业务方法它就会在方法的执行前打开事务,在方法的执行后结束事务。
那么在采用JDBC+Spring开发应用的过程中,有些同学喜欢把数据库的连接信息放在一个属性文件中,那么我们也可以采用Spring提供的占位符方式,从属性文件中把数据引入进来。
现在在类路径底下建个属性文件jdbc.properties,加入相应的信息
然后在配置文件中如何把它引入进来呢?Spring给我们提供了一个配置节点 <context:property-placeholder location=“jdbc.properties”/>,可以采用占位符的方式把属性文件里面的值引入到配置文件中
beans.xml
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/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${driverClassName}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
<!-- 连接池启动时的初始值 -->
<property name="initialSize" value="${initialSize}"/>
<!-- 连接池的最大值 -->
<property name="maxActive" value="${maxActive}"/>
<!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->
<property name="maxIdle" value="${maxIdle}"/>
<!-- 最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 -->
<property name="minIdle" value="${minIdle}"/>
</bean>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="personService" class="cn.itcast.service.impl.PersonServiceBean">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
我们采用类似EL表达式这种语法就可以从属性文件中根据给定的key获取属性文件里配置的内容,然后把内容应用进来,当然这个过程都是由Spring来做的。
改成这样后,运行单元测试代码,发现以前的程序还可以使用。
该节目录结构如图:
Java代码
package cn.itcast.service.impl;
import java.util.List;
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Transactional;
import cn.itcast.bean.Person;
import cn.itcast.service.PersonService;
//@Transactional
public class PersonServiceBean implements PersonService {
//private DataSource dataSource;
/*
接下来就可以通过dataSource进行操作,但是我们不会直接面对dataSource进行操作,也建议大家不要面对
他进行操作,我们应该采用Spring为我们提供的JdbcTemplate这个辅助类来对JDBC进行操作,
因为这个类给我们封装了比较多的JDBC操作代码,我们只要调用它的方法就可以实现某些业务逻辑了
因为我们目前是通过jdbcTemplate这个类来对JDBC进行操作,所以数据源dataSource没必要再对它进行保存,
所以comment了dataSource的定义
*/
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
//把数据源dataSource作为构造器参数传进去
}
public void delete(Integer personid) {
jdbcTemplate.update("delete from person where id=?", new Object[]{personid},
new int[]{java.sql.Types.INTEGER});
}
public Person getPerson(Integer personid) {
return (Person)jdbcTemplate.queryForObject("select * from person where id=?", new Object[]{personid},
new int[]{java.sql.Types.INTEGER}, new PersonRowMapper());
/*
第三个参数代表:当查询到这条记录的时候,它会调用第三个对象的一个回调方法,只要实现了这个回调方法,那么就会调用
*/
}
@SuppressWarnings("unchecked")
public List<Person> getPersons() {
return (List<Person>)jdbcTemplate.query("select * from person", new PersonRowMapper());
}
public void save(Person person) {
jdbcTemplate.update("insert into person(name) values(?)", new Object[]{person.getName()},
new int[]{java.sql.Types.VARCHAR});
}
public void update(Person person) {
jdbcTemplate.update("update person set name=? where id=?", new Object[]{person.getName(), person.getId()},
new int[]{java.sql.Types.VARCHAR, java.sql.Types.INTEGER});
}
}
package cn.itcast.service.impl; import java.util.List; import javax.sql.DataSource; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.transaction.annotation.Transactional; import cn.itcast.bean.Person; import cn.itcast.service.PersonService; //@Transactional public class PersonServiceBean implements PersonService { //private DataSource dataSource; /* 接下来就可以通过dataSource进行操作,但是我们不会直接面对dataSource进行操作,也建议大家不要面对 他进行操作,我们应该采用Spring为我们提供的JdbcTemplate这个辅助类来对JDBC进行操作, 因为这个类给我们封装了比较多的JDBC操作代码,我们只要调用它的方法就可以实现某些业务逻辑了 因为我们目前是通过jdbcTemplate这个类来对JDBC进行操作,所以数据源dataSource没必要再对它进行保存, 所以comment了dataSource的定义 */ private JdbcTemplate jdbcTemplate; public void setDataSource(DataSource dataSource) { this.jdbcTemplate = new JdbcTemplate(dataSource); //把数据源dataSource作为构造器参数传进去 } public void delete(Integer personid) { jdbcTemplate.update("delete from person where id=?", new Object[]{personid}, new int[]{java.sql.Types.INTEGER}); } public Person getPerson(Integer personid) { return (Person)jdbcTemplate.queryForObject("select * from person where id=?", new Object[]{personid}, new int[]{java.sql.Types.INTEGER}, new PersonRowMapper()); /* 第三个参数代表:当查询到这条记录的时候,它会调用第三个对象的一个回调方法,只要实现了这个回调方法,那么就会调用 */ } @SuppressWarnings("unchecked") public List<Person> getPersons() { return (List<Person>)jdbcTemplate.query("select * from person", new PersonRowMapper()); } public void save(Person person) { jdbcTemplate.update("insert into person(name) values(?)", new Object[]{person.getName()}, new int[]{java.sql.Types.VARCHAR}); } public void update(Person person) { jdbcTemplate.update("update person set name=? where id=?", new Object[]{person.getName(), person.getId()}, new int[]{java.sql.Types.VARCHAR, java.sql.Types.INTEGER}); } }
PersonRowMapper.java
Java代码
package cn.itcast.service.impl;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.jdbc.core.RowMapper;
import cn.itcast.bean.Person;
public class PersonRowMapper implements RowMapper {
/*
有同学会问,rs这个记录集进来时为什么不next一下?
是因为外部调用这个方法时已经在外面做了一下这种操作:if(rs.next())
外面做了这个操作,里面就不用再做这种操作
*/
public Object mapRow(ResultSet rs, int index) throws SQLException {
Person person = new Person(rs.getString("name"));
person.setId(rs.getInt("id"));
return person;
}
}
package cn.itcast.service.impl; import java.sql.ResultSet; import java.sql.SQLException; import org.springframework.jdbc.core.RowMapper; import cn.itcast.bean.Person; public class PersonRowMapper implements RowMapper { /* 有同学会问,rs这个记录集进来时为什么不next一下? 是因为外部调用这个方法时已经在外面做了一下这种操作:if(rs.next()) 外面做了这个操作,里面就不用再做这种操作 */ public Object mapRow(ResultSet rs, int index) throws SQLException { Person person = new Person(rs.getString("name")); person.setId(rs.getInt("id")); return person; } }
建一个单元测试:PersonServiceTest.java
Java代码
package junit.test;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.itcast.bean.Person;
import cn.itcast.service.PersonService;
public class PersonServiceTest {
private static PersonService personService;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
try {
ApplicationContext cxt = new ClassPathXmlApplicationContext("beans.xml");
personService = (PersonService) cxt.getBean("personService");
} catch (RuntimeException e) {
e.printStackTrace();
}
}
@Test public void save(){
for(int i=0; i<5; i++)
personService.save(new Person("传智播客"+ i));
}
@Test public void getPerson(){
Person person = personService.getPerson(1);
System.out.println(person.getName());
}
@Test public void update(){
Person person = personService.getPerson(1);
person.setName("张xx");
personService.update(person);
}
@Test public void delete(){
personService.delete(1);
}
@Test public void getBeans(){
for(Person person : personService.getPersons()){
System.out.println(person.getName());
}
}
}
package junit.test; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import cn.itcast.bean.Person; import cn.itcast.service.PersonService; public class PersonServiceTest { private static PersonService personService; @BeforeClass public static void setUpBeforeClass() throws Exception { try { ApplicationContext cxt = new ClassPathXmlApplicationContext("beans.xml"); personService = (PersonService) cxt.getBean("personService"); } catch (RuntimeException e) { e.printStackTrace(); } } @Test public void save(){ for(int i=0; i<5; i++) personService.save(new Person("传智播客"+ i)); } @Test public void getPerson(){ Person person = personService.getPerson(1); System.out.println(person.getName()); } @Test public void update(){ Person person = personService.getPerson(1); person.setName("张xx"); personService.update(person); } @Test public void delete(){ personService.delete(1); } @Test public void getBeans(){ for(Person person : personService.getPersons()){ System.out.println(person.getName()); } } }
运行save这个单元测试,数据库表记录是:看图
运行getPerson这个单元测试,控制台输出:传智播客0运行update这个单元测试,数据库表记录是:看图
运行delete这个单元测试,数据库表记录是:看图
运行getBeans这个单元测试,控制台输出:
传智播客1
传智播客2
传智播客3
传智播客4
这些就是JDBC + Spring的操作,但是大家留意一下,我们这个bean目前并没有受Spring的事务管理,为什么呢?因为我们并没有为这个bean定义@Transactional这个注解。 如果我们不定义这个注解的情况下呢,
Java代码
public void delete(Integer personid) {
jdbcTemplate.update("delete from person where id=?", new Object[]{personid},
new int[]{java.sql.Types.INTEGER});
}
这些jdbc的语句,它的执行都会在各自的事务中执行,如果说delete这个方法有两条语句
public void delete(Integer personid) {
jdbcTemplate.update("delete from person where id=?", new Object[]{personid},
new int[]{java.sql.Types.INTEGER});
jdbcTemplate.update("delete from person where id=?", new Object[]{personid},
new int[]{java.sql.Types.INTEGER});
}
public void delete(Integer personid) { jdbcTemplate.update("delete from person where id=?", new Object[]{personid}, new int[]{java.sql.Types.INTEGER}); } 这些jdbc的语句,它的执行都会在各自的事务中执行,如果说delete这个方法有两条语句 public void delete(Integer personid) { jdbcTemplate.update("delete from person where id=?", new Object[]{personid}, new int[]{java.sql.Types.INTEGER}); jdbcTemplate.update("delete from person where id=?", new Object[]{personid}, new int[]{java.sql.Types.INTEGER}); }
那么每条语句都会在各自的事务中执行,他们是无法保证在同一个事务中执行的,这时候会出现一些问题。
我们为了保证这两条语句在同一条事务中执行,我们应该使用容器给我们提供的申明事务@Transactional这个注解,申明了事务,那么默认它会使得delete这个方法需要事务,然后保证里面的操作在同一事务里执行,所以在业务bean PersonServiceBean上面别忘了加上@Transactional事务注解
PersonServiceBean.java
Java代码
@Transactional
public class PersonServiceBean implements PersonService {
........................
}
@Transactional public class PersonServiceBean implements PersonService { ........................ }
加上了这个注解后,就明确告诉Spring容器这个PersonServiceBean现在是要受Spring的事务管理的,这样bean底下所有的业务方法它就会在方法的执行前打开事务,在方法的执行后结束事务。
那么在采用JDBC+Spring开发应用的过程中,有些同学喜欢把数据库的连接信息放在一个属性文件中,那么我们也可以采用Spring提供的占位符方式,从属性文件中把数据引入进来。
现在在类路径底下建个属性文件jdbc.properties,加入相应的信息
然后在配置文件中如何把它引入进来呢?Spring给我们提供了一个配置节点 <context:property-placeholder location=“jdbc.properties”/>,可以采用占位符的方式把属性文件里面的值引入到配置文件中
beans.xml
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/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${driverClassName}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
<!-- 连接池启动时的初始值 -->
<property name="initialSize" value="${initialSize}"/>
<!-- 连接池的最大值 -->
<property name="maxActive" value="${maxActive}"/>
<!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->
<property name="maxIdle" value="${maxIdle}"/>
<!-- 最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 -->
<property name="minIdle" value="${minIdle}"/>
</bean>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="personService" class="cn.itcast.service.impl.PersonServiceBean">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
<?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/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <context:property-placeholder location="classpath:jdbc.properties"/> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${driverClassName}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> <!-- 连接池启动时的初始值 --> <property name="initialSize" value="${initialSize}"/> <!-- 连接池的最大值 --> <property name="maxActive" value="${maxActive}"/> <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 --> <property name="maxIdle" value="${maxIdle}"/> <!-- 最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 --> <property name="minIdle" value="${minIdle}"/> </bean> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <tx:annotation-driven transaction-manager="txManager"/> <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean"> <property name="dataSource" ref="dataSource"/> </bean> </beans>
我们采用类似EL表达式这种语法就可以从属性文件中根据给定的key获取属性文件里配置的内容,然后把内容应用进来,当然这个过程都是由Spring来做的。
改成这样后,运行单元测试代码,发现以前的程序还可以使用。
该节目录结构如图:
相关文章推荐
- Spring集成的JDBC编码和事务管理
- 【Spring实战】—— 16 基于JDBC持久化的事务管理
- 【Java EE 学习 52】【Spring学习第四天】【Spring与JDBC】【JdbcTemplate创建的三种方式】【Spring事务管理】【事务中使用dbutils则回滚失败!!!??】
- tapestry5 集成 spring 的事务管理
- mybatis集成spring的事务管理
- 【Spring 事务管理系列之一】Spring使用JDBC的事务管理例子
- MyBatis(5):MyBatis 集成 Spring 事务管理(上)
- Spring.NET 1.3.2 集成 NHibernate 3.2 - 5 - 事务管理
- spring的jdbc事务管理和JTA有什么区别?
- Spring整合JDBC以及AOP管理事务
- mybatis集成spring的事务管理
- spring 管理 jdbc 事务
- Spring学习(四)Jdbc连接池交个spring管理和事务操作
- MyBatis(5):MyBatis 集成 Spring 事务管理(上)
- 《Spring 2.0技术手册》 读书笔记七-Spring的DAO框架(3)-JDBC事务管理
- spring中JDBC 声明式事务管理
- Spring JDBC使用、事务管理
- mybatis集成spring的事务管理
- Spring JDBC和Hibernate混用时,如何配置事务管理
- 【Spring实战】—— 16 基于JDBC持久化的事务管理