作用:保证数据库的完整性。
事务概念:在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。
举例:银行转账。A账户向B账户转1000元,这时A应当减少1000元,而B增加1000元,这是正确的处理结果。
银行系统出错,会出现两种情况:
(1)A账户少了1000元,而B的账户却没有增加1000元;
(2)A账户没有减少1000元,而这时B的账户却增加了1000元。
客户和银行都不愿看到这种情形,。那么有没有措施保证转帐得顺利进行呢?这种措施就是——数据库事务管理机制。
相关内容:
Spring的数据库编程(不涉及事务管理情况),
编程式事务管理 a.基于底层API编程事务管理 b.基于TransactionTemplate编程事务管理
声明式事务管理
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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 通过扫描器扫描包(或子包),将带有注解的类注册为Bean -->
<context:component-scan base-package="jdbc"/>
<!--配置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!-- 数据库驱动 -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<!-- 连接数据库ulr -->
<property name="url" value="jdbc:mysql://localhost:3306/user?characterEncoding=utf8"></property>
<!-- 用户名 -->
<property name="username" value="root"></property>
<!-- 用户密码 -->
<property name="password" value="123456"></property>
</bean>
<!-- 配置JDBC模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
实体类:
package jdbc;
public class MyUser {
private Integer id;
private String name;
private String sex;
private Integer age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return id+" "+name+" "+sex+" "+age;
}
}
数据库访问层:
package jdbc;
import java.util.List;
public interface TestDao {
public int update(String sql,Object[] param);
public List<MyUser> query(String sql,Object[] param);
}
package jdbc;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
@Repository("testDao")
public class TestDaoImp implements TestDao{
@Autowired
private JdbcTemplate jdbcOperate;
@Override
public int update(String sql, Object[] param) {
return jdbcOperate.update(sql, param);
}
@Override
public List<MyUser> query(String sql, Object[] param) {
// TODO Auto-generated method stub
RowMapper<MyUser> mapper=new BeanPropertyRowMapper<MyUser>(MyUser.class);
return jdbcOperate.query(sql, mapper,param);
}
}
测试类:
package Test;
import java.util.Iterator;
import java.util.List;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import jdbc.MyUser;
import jdbc.TestDao;
public class TestJdbc {
public static void main(String[] args) {
//获取Application容器
ApplicationContext appcon=new ClassPathXmlApplicationContext("ApplicationContext.xml");
//获取增强后的数据库操作对象
TestDao jdbcop= (TestDao) appcon.getBean("testDao");//param表示参数,可以指代一组数据
/*
* =======================数据更新----插入
*/
//数据插入sql语句
String insertSql="insert into user values(?,?,?,?)";
//数据paramd的值与insertsql中的?一一对应
Object param1[]= {1,"chaokaidi1","男",33};
Object param2[]= {3,"chaokaidi2","男",44};
Object param3[]= {6,"chaokaidi3","男",21};
Object param4[]= {9,"chaokaidi4","女",34};
//添加用户
jdbcop.update(insertSql, param1);
jdbcop.update(insertSql, param2);
jdbcop.update(insertSql, param3);
jdbcop.update(insertSql, param4);
System.out.println("更新!!!");
/*
* ========================数据查询
*/
String querySql="select * from user";
List<MyUser> MyUserList=jdbcop.query(querySql, null);
for(Iterator iterator = MyUserList.iterator(); iterator.hasNext();) {
MyUser myUser = (MyUser) iterator.next();
System.out.println(myUser.toString());//duplicate:完全一样的
}
}
}
编程事务管理——基于底层API(PlatformTransactionManager,TransactionDefinition和TransactionStatus接口)
注:DataSourceTransactionManager实现了PlatformTransactionManager接口
DefaultTransactionDefinition实现了TransactionDefinition接口
配置文件添加:
<!-- 添加事务回滚 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
测试代码修改:
package Test;
import java.util.Iterator;
import java.util.List;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import jdbc.MyUser;
import jdbc.TestDao;
public class TestJdbc {
public static void main(String[] args) {
//获取Application容器
ApplicationContext appcon=new ClassPathXmlApplicationContext("ApplicationContext.xml");
//获取增强后的数据库操作对象
TestDao jdbcop= (TestDao) appcon.getBean("testDao");//param表示参数,可以指代一组数据
DataSourceTransactionManager tm=(DataSourceTransactionManager) appcon.getBean("txManager");
TransactionDefinition definition=new DefaultTransactionDefinition();
//开启事务
TransactionStatus ts=tm.getTransaction(definition);
String message="执行成功";
try {
/*
* =======================数据更新----插入
*/
//数据插入sql语句
String insertSql="insert into user values(?,?,?,?)";
//数据paramd的值与insertsql中的?一一对应
Object param1[]= {1,"chaokaidi1","男",33};
Object param2[]= {3,"chaokaidi2","男",44};
Object param3[]= {6,"chaokaidi3","男",21};
Object param4[]= {9,"chaokaidi4","女",34};
//添加用户
jdbcop.update(insertSql, param1);
jdbcop.update(insertSql, param2);
jdbcop.update(insertSql, param3);
jdbcop.update(insertSql, param4);
System.out.println("更新!!!");
/*
* ========================数据查询
*/
String querySql="select * from user";
List<MyUser> MyUserList=jdbcop.query(querySql, null);
for(Iterator iterator = MyUserList.iterator(); iterator.hasNext();) {
MyUser myUser = (MyUser) iterator.next();
System.out.println(myUser.toString());//duplicate:完全一样的
}
tm.commit(ts);
}catch (Exception e) {
tm.rollback(ts);
message="事务进行回滚";
}finally {
System.out.println(message);
}
}
}
编程事务管理——基于TransactionTemplate
注:TransactionTemplate的execute方法有一个TransactionCallbac接口类型的参数,该接口定义了doInTransaction方法,通过内部内类的方式实现TransactionCallback接口,并在doIntTransaction方法内书写业务逻辑代码。
配置文件添加:
<!-- 为事务管理器txManager创建transcationTemplate -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="txManager"></property>
</bean>
测试代码修改:
package Test;
import java.util.Iterator;
import java.util.List;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import jdbc.MyUser;
import jdbc.TestDao;
public class TestJdbc {
public static void main(String[] args) {
//获取Application容器
ApplicationContext appcon=new ClassPathXmlApplicationContext("ApplicationContext.xml");
//获取增强后的数据库操作对象
TestDao jdbcop= (TestDao) appcon.getBean("testDao");//param表示参数,可以指代一组数据
//==============基于底层API进行事务处理
// DataSourceTransactionManager tm=(DataSourceTransactionManager) appcon.getBean("txManager");
// //默认事务定义
// TransactionDefinition definition=new DefaultTransactionDefinition();
// //开启事务
// TransactionStatus ts=tm.getTransaction(definition);
//=================================================
String message="执行成功";
TransactionTemplate template1 = (TransactionTemplate) appcon.getBean("transactionTemplate");
template1.execute(new TransactionCallback<Object>() {
@Override
public Object doInTransaction(TransactionStatus arg0) {
String message="执行成功!!";
try {
/*
* =======================数据更新----插入
*/
//数据插入sql语句
String insertSql="insert into user values(?,?,?,?)";
//数据paramd的值与insertsql中的?一一对应
Object param1[]= {20,"chaokaidi1","男",33};
Object param2[]= {3,"chaokaidi2","男",44};
Object param3[]= {6,"chaokaidi3","男",21};
Object param4[]= {9,"chaokaidi4","女",34};
//添加用户
jdbcop.update(insertSql, param1);
jdbcop.update(insertSql, param2);
jdbcop.update(insertSql, param3);
jdbcop.update(insertSql, param4);
System.out.println("更新!!!");
/*
* ========================数据查询
*/
String querySql="select * from user";
List<MyUser> MyUserList=jdbcop.query(querySql, null);
for(Iterator iterator = MyUserList.iterator(); iterator.hasNext();) {
MyUser myUser = (MyUser) iterator.next();
System.out.println(myUser.toString());//duplicate:完全一样的
}
System.out.println("执行成功!!!");
return null;
}catch (Exception e) {
message="事务回滚!!";
}
return message;
}
});
}
}
声明式事务管理
Spring的声明式事务管理是通过AOP技术实现的事务管理,我其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
优点:不需要通过编程的方式管理事务,不需要在业务逻辑中掺杂事务处理代码,只需要进行相关规则的声明。
基于xml式的声明式的事务管理
目录:
jar包目录:
工程目录:
dao层:
接口
package com.dao;
public interface TestDao {
public int save(String sql,Object []param);
public int delete(String sql,Object []param);
}
实现类:
package com.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository("testDao")
public class TestDaoImp implements TestDao{
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public int save(String sql, Object[] param) {
return jdbcTemplate.update(sql,param);
}
@Override
public int delete(String sql, Object[] param) {
// TODO Auto-generated method stub
return jdbcTemplate.update(sql,param);
}
}
service层:
接口:
package com.service;
public interface TestService {
public int save(String sql,Object []param);
public int delete(String sql,Object []param);
}
实现类:
package com.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.dao.TestDao;
@Service("service")
@Transactional
public class TestServiceImp implements TestService{
@Autowired
TestDao testdao;
@Override
public int save(String sql, Object[] param) {
return testdao.save(sql, param);
}
@Override
public int delete(String sql, Object[] param) {
return testdao.delete(sql, param);
}
}
controller:
package com.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import com.service.TestService;
@Controller("controller")
public class TestController {
@Autowired
private TestService service;
public String test() {
//用于通知处理消息
String message="";
//删除sql语句
String deleteSql="delete form user";
//数据库插入语句
String saveSql="insert into user values(?,?,?,?)";
Object []param= {30,"duanhao","男",23};
try {
//service.delete(deleteSql, null);
service.save(saveSql, param);
//service.save(saveSql, param);
message="执行成功!!!";
} catch (Exception e) {
message="主键重复,事务回滚";
}
return message;
}
}
Test:主函数
package com.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.controller.TestController;
public class Test {
public static void main(String[] args) {
ApplicationContext appContext=new ClassPathXmlApplicationContext("com/xml/ApplicationContext.xml");
TestController controller=(TestController) appContext.getBean("controller");
System.out.println(controller.test());
}
}
ApplicationContext:
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- <aop:aspectj-autoproxy/> -->
<!-- 指定要扫描的包,是注解生效 -->
<context:component-scan base-package="com"></context:component-scan>
<!-- 配置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!-- Mysql驱动 -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<!-- 连接数据库的URL -->
<property name="url" value="jdbc:mysql://localhost:3306/user?characterEncoding=utf8"></property>
<!-- 用户名 -->
<property name="username" value="root"></property>
<!-- 用户密码 -->
<property name="password" value="123456"></property>
</bean>
<!-- 配置JDBC模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 为数据源添加事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 编写通知声明事务 -->
<tx:advice id="myAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="*"></tx:method>
</tx:attributes>
</tx:advice>
<!-- 编写AOP,让Spring自动对目标对象生成代理,b 需要使用AspecxtJ的表达式 -->
<aop:config>
<aop:pointcut expression="execution(* com.service.*.*(..))" id="txPointCut"></aop:pointcut>
<aop:advisor advice-ref="myAdvice" pointcut-ref="txPointCut"></aop:advisor>
</aop:config>
</beans>
基于@Transactional注解的声明式事务管理
注:可以作用于接口,接口方法,类以及类的方法上。
当作用于类上时,该类所有的public方法都将具有该类型的事务属性,当然也可以在方法级上,覆盖类级别的定义。
由上工程配置文件修改为:
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- <aop:aspectj-autoproxy/> -->
<!-- 指定要扫描的包,是注解生效 -->
<context:component-scan base-package="dao"></context:component-scan>
<context:component-scan base-package="service"></context:component-scan>
<context:component-scan base-package="controller"></context:component-scan>
<!-- 配置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!-- Mysql驱动 -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<!-- 连接数据库的URL -->
<property name="url" value="jdbc:mysql://localhost:3306/user?characterEncoding=utf8"></property>
<!-- 用户名 -->
<property name="username" value="root"></property>
<!-- 用户密码 -->
<property name="password" value="123456"></property>
</bean>
<!-- 配置JDBC模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 为数据源添加事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 为事务管理器注册注解驱动器 -->
<tx:annotation-driven transaction-manager="txManager"/>
</beans>
Service层修改:
package service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import dao.TestDao;
@org.springframework.stereotype.Service
@Transactional
public class ServiceImp implements Service {
@Autowired
private TestDao testDao;
@Override
public int save(String sql, Object[] param) {
return testDao.save(sql, param);
}
@Override
public int delete(String sql, Object[] param) {
// TODO Auto-generated method stub
return testDao.delete(sql, param);
}
}