spring框架。声明事务全xml方式和半xml半注解方式
spring的声明式事务
事务有什么特性: ACID
原子性: 一件完成的事情,要不全部成功 要不全部失败
转账: 加钱 减钱
一致性: 事务的前后,数据总数不发生变化
jack 1000 rose 1000 2000
jack 500 rose 1500 2000
持久性: 只要事务已完成(提交),数据就会到数据库中
隔离性: 事务具备隔离性,如果没有隔离性,会发送读取数据的问题
不具备隔离性的话,会发生什么问题:
会发送读取数据的问题
脏读: 在一个事务中,读取到了另一个事务还没有提交的数据 必须杜绝的
ps:所有的数据库都自动避免的脏读
重复读:在一个事务中,2次读取到的数据内容不一致(update) 可以允许
虚读/幻读:在一个事务中,2次读取到的数据内容不一致(insert) 可以允许
可以通过调整数据库的隔离级别,避免以上问题的发生:
设置隔离级别
read uncommitted 效率最高 安全最低
read committed oracle
repeatable read mysql
serializable 安全最高 效率最低
转账案例
1 导包
spring-tx.jar
2 事务依赖aop
AOP联盟
spring-aop.jar
aspectj.jar
spring-aspects.jar
引入tx aop约束文件
3 编码
1 确定目标类 (TranFerServiceImpl --tranfer)
2 确定切面类 (用人家的 因为spring有一个类,里面都是事务的方法)
DataSourceTransactionManager
提交
回滚
增强方法:都是关于事务的
细节: 得为配了这些事务增强方法的tanfer配置一些事务参数
是否只读
超时时间
传播行为
3 配置织入
专门针对事务的标签
指定那个事务用于那个切入点
jdbc.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/atm?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true
jdbc.username=root
jdbc.password=123
#jdbc.driver=com.mysql.jdbc.Driver
#jdbc.url=jdbc:oracle://localhost:3306/hibernate
#jdbc.username=root
#jdbc.password=1234
#jdbc.driver=com.mysql.jdbc.Driver
#jdbc.url=jdbc:db2://localhost:3306/hibernate
#jdbc.username=root
#jdbc.password=1234
bean.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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- spring加载src下的properties文件 -->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!-- c3p0 -->
<bean id="c3p0" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- jdbcTemplate -->
<bean id="jdbctemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="c3p0"></property>
</bean>
<!-- tranFerDao -->
<bean id="tranFerDao" class="com.it.daoimpl.TranFerDaoImpl">
<property name="jdbctemplate" ref="jdbctemplate"></property>
</bean>
<!-- tranFerService 目标类 -->
<bean id="tranFerService" class="com.it.serviceimpl.TranFerServiceImpl">
<property name="tranFerDao" ref="tranFerDao"></property>
</bean>
<!-- 切面类 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="c3p0"> </property>
</bean>
<!-- 配置DataSourceTransactionManager里面事务方法的一些参数
不写 该方法使用的事务参数都是默认值
-->
<tx:advice transaction-manager="transactionManager" id="txadvice">
<tx:attributes>
<!-- 指定方法名称:是业务核心方法
read-only:是否是只读事务。默认 false,不只读。
isolation:指定事务的隔离级别。默认值是使用数据库的默认隔离级别。
propagation:指定事务的传播行为。 timeout:指定超时时间。默认值为:-1。永不超时。
rollback-for:用于指定一个异常,当执行产生该异常时,事务回滚。产生其他异常,事务不回滚。 没有默认值,任何异常都回滚。
no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时,事务回 滚。没有默认值,任何异常都回滚。 -->
<tx:method name="tranfer"/>
</tx:attributes>
</tx:advice>
<!-- 织入 -->
<aop:config>
<aop:pointcut expression="execution(* com.it.serviceimpl.TranFerServiceImpl.tranfer(..))" id="pointcut"/>
<!-- 针对事务的配置标签 -->
<aop:advisor advice-ref="txadvice" pointcut-ref="pointcut"/>
</aop:config>
</beans>
test方法
package com.it.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.it.service.TranFerService;
import com.it.serviceimpl.TranFerServiceImpl;
public class TranFerTest {
public static void main(String[] args) {
//使用JDK动态代理的方法,使用接口来实现代理,需要使用被代理者来增强
//使用如果使用CGlib动态代理的方法,只需要使用代理者来增强
ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
TranFerService tranferserviceimpl= (TranFerService) context.getBean("tranFerService");
tranferserviceimpl.tranfer("jack","tom",500);
}
}
TranFerService
package com.it.service;
public interface TranFerService {
public void tranfer(String toUser,String inUser,double Money);
}
TranFerServiceImpl
package com.it.serviceimpl;
import com.it.daoimpl.TranFerDaoImpl;
import com.it.service.TranFerService;
public class TranFerServiceImpl implements TranFerService {
private TranFerDaoImpl tranFerDao;
public void setTranFerDao(TranFerDaoImpl tranFerDao) {
this.tranFerDao = tranFerDao;
}
@Override
public void tranfer(String toUser, String inUser, double Money) {
//加钱
tranFerDao.toMoney(toUser,Money);
//int i=1/0;
//减钱
tranFerDao.inMoney(inUser,Money);
}
}
TranFerDao
package com.it.dao;
public interface TranFerDao {
public void toMoney(String toUser, double money);
public void inMoney(String inUser, double money);
}
TranFerDaoImpl
package com.it.daoimpl;
import org.springframework.jdbc.core.JdbcTemplate;
import com.it.dao.TranFerDao;
public class TranFerDaoImpl implements TranFerDao {
private JdbcTemplate jdbctemplate;
public void setJdbctemplate(JdbcTemplate jdbctemplate) {
this.jdbctemplate = jdbctemplate;
}
//加钱
public void toMoney(String toUser, double money) {
String sql="update atm set money = money + ? where username = ?";
jdbctemplate.update(sql,money,toUser);
}
//减钱
public void inMoney(String inUser, double money) {
String sql="update atm set money = money - ? where username = ?";
jdbctemplate.update(sql,money,inUser);
}
}
注解配置: xml+注解(企业开发)
别人的 用xml
自己的 用注解
<context:component-scan base-package="com.it"></context:component-scan>
事务的注解2步:
指定开启事务的注解 告诉spirng使用的事务方法是谁的方法
<tx:annotation-driven transaction-manager="PlatformTransactionManager"/>
在方法上或则是类上配置:
@Transactional
jdbc.properties同上
bean.xml
配置事务管理器并注入数据源
<tx:annotation-driven transaction-manager="PlatformTransactionManager"/>
<?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"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- spring加载src下的properties文件 -->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!-- c3p0 -->
<bean id="c3p0" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- jdbcTemplate -->
<bean id="jdbctemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="c3p0"></property>
</bean>
<!-- 切面类 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="c3p0"> </property>
</bean>
<!-- 自己的类 -->
<!-- 开启注解扫描器 -->
<context:component-scan base-package="com.it"></context:component-scan>
<!-- 开启事务的注解配置 告诉使用的是哪个类下的事务 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
test方法同上
TranFerService.java同上
TranFerServiceImpl
在业务层使用@Transactional 注解
该注解的属性和 xml 中的属性含义一致。
该注解可以出现在接口上,类上和方法上。
出现接口上,表示该接口的所有实现类都有事务支持。
出现在类上,表示类中所有方法有事务支持 出现在方法上,表示方法有事务支持。
以上三个位置的优先级:方法>类>接口
package com.it.serviceimpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.it.daoimpl.TranFerDaoImpl;
import com.it.service.TranFerService;
@Service("tranFerService")
@Transactional
public class TranFerServiceImpl implements TranFerService {
@Autowired
private TranFerDaoImpl tranFerDao;
@Override
public void tranfer(String toUser, String inUser, double Money) {
//加钱
tranFerDao.toMoney(toUser,Money);
int i=1/0;
//减钱
tranFerDao.inMoney(inUser,Money);
}
}
TranFerDao同上
TranFerDaoImpl
package com.it.daoimpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import com.it.dao.TranFerDao;
@Repository("tranFerDao")
public class TranFerDaoImpl implements TranFerDao {
@Autowired
private JdbcTemplate jdbctemplate;
//加钱
public void toMoney(String toUser, double money) {
String sql="update atm set money = money + ? where username = ?";
jdbctemplate.update(sql,money,toUser);
}
//减钱
public void inMoney(String inUser, double money) {
String sql="update atm set money = money - ? where username = ?";
jdbctemplate.update(sql,money,inUser);
}
}
全注解的方式配置事务(了解即可)
条件: 需要注解类
@EnableTransactionManagement
// <tx:annotation-driven transaction-manager="platformTransactionManager"/>
@Qualifier("c3p0") DataSource ds:参数配置