- 编写事务管理工具类并分析连接和线程解绑
- 编写业务层和持久层事务控制代码并配置spring的ioc
- 测试转账并分析案例中的问题
工具类:TransactionManager的实现
在这里插入*
* 和事务管理相关的工具类,它包含了: 开启事务,提交事务,回滚事务和释放连接*/
public class TransactionManager {
private ConnectionUtils connectionUtils;
public void setConnectionUtils(ConnectionUtils connectionUtils) {
this.connectionUtils = connectionUtils;
}
/*
*开启事务 */
public void beginTransaction() {
try {
connectionUtils.getThreadConnection().setAutoCommit(false);
}catch (Exception e){
e.printStackTrace();
}
}
/*
*提交事务 */
public void commit() {
try {
connectionUtils.getThreadConnection().commit();
}catch (Exception e){
e.printStackTrace();
}
}
/*
*回滚事务 */
public void rollback() {
try {
connectionUtils.getThreadConnection().rollback();
}catch (Exception e){
e.printStackTrace();
}
}
/*
*释放事务 */
public void release() {
try {
connectionUtils.getThreadConnection().close(); //还回了连接池中
connectionUtils.removeConnection();
}catch (Exception e){
e.printStackTrace();
}
}
}代码片
连接的工具类: ConnectionUtils
/*
* 连接的工具类,它用于从数据源中获取一个连接,并且实现和线程的绑定*/
public class ConnectionUtils {
private ThreadLocal<Connection> t1 = new ThreadLocal<Connection>();
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
/*
* 获取当前线程上的连接*/
public Connection getThreadConnection() {
//1.先从ThreadLocal上获取
Connection conn = t1.get();
try {
//2.判断当前线程上是否有连接
if (conn == null) {
//3.从数据源中获取一个连接,并且存入ThreadLocal中
conn = dataSource.getConnection();
t1.set(conn);
}
//4.返回当前线程上的连接
return conn;
}catch (Exception e){
throw new RuntimeException(e);
}
}
/*
* 把连接和线程解绑*/
public void removeConnection() {
t1.remove();
}
}
- 使用以上两个类,实现转账功能
public void transfer(String sourceName, String targetName, Float money) {
try {
//1.开启事务
tsManager.beginTransaction();
//2.执行操作
//2.1.根据名称查询转出账户
Account source = accountDao.findAccountByName(sourceName);
//2.2.根据名称查询转入账户
Account target = accountDao.findAccountByName(targetName);
//2.3.转出账户减钱
source.setMoney(source.getMoney() - money);
//2.4.转入账户加钱
target.setMoney(target.getMoney() + money);
//2.5.更新转出账户
accountDao.updateAccount(source);
//2.6.更新转入账户
accountDao.updateAccount(target);
//3.提交事务
tsManager.commit();
}catch (Exception e){
//4.回滚操作
tsManager.rollback();
e.printStackTrace();
}finally {
//5.释放连接
tsManager.release();
}
动态代理学习:
- 建立一个 Producer 类作为生产者
基于子类的生产者类:
public class Producer {
/*
* 销售*/
public void saleProduct(float money) {
System.out.println("销售产品,并拿到钱:" + money);
}
}
基于接口的生产者类:
/*
* 一个生产者*/
public class Producer implements IProducer {
/*
* 销售*/
public void saleProduct(float money) {
System.out.println("销售产品,并拿到钱:" + money);
}
/*
* 售后*/
public void afterService(float money) {
System.out.println("提供售后服务,并拿到钱:" + money);
}
}
基于接口的生产者的接口:
/*
* 对生产厂家要求的接口*/
public interface IProducer {
/*
* 销售*/
public void saleProduct(float money);
/*
* 售后*/
public void afterService(float money);
}
- 1.基于接口的动态代理:
/*
* 模拟一个消费者*/
public class Client {
public static void main(String[] args) {
final Producer producer = new Producer();
producer.saleProduct(10000f);
/*
* 动态代理:
* 特点: 字节码随用随创建,随用随加载
* 作用:不修改源码的基础上对方法增强
* 分类
* 基于接口的动态代理
* 基于子类的动态代理
* 基于接口的动态代理:
* 涉及的类:Proxy
* 提供者:JDK官方
* 如何创建代理对象:
* 使用Proxy类中的newProxyInstance方法
* 创建代理对象的要求:
* 被代理类最少实现一个接口,如果没有则不能使用
* newProxyInstance方法的参数:
* ClassLoader:类加载器
* 它是用于加载代理对象字节码的,写的是和被代理对象相同的类加载器。固定写法
* Class[]:字节码数组
* 它是用于让代理对象和被代理对象有相同方法。固定写法。
* InvocationHandler:用于提供增强的代码
* 它是让我们写如何代理。我们一般都是一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。
* 此接口的实现类都是谁用谁写。
* */
IProducer proxyProducer = (IProducer)Proxy.newProxyInstance(producer.getClass().getClassLoader(),
producer.getClass().getInterfaces(),
new InvocationHandler() {
/*
proxy:代理对象的引用
method:当前执行的方法
args:当前执行方法所需的参数和被代理对象有相同的返回值
作用:执行被代理对象的任何接口方法都会经过该方法*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//提供增强的代码
Object returnValue = null;
//1.获取方法执行的参数
Float money = (Float) args[0];
//2.判断当前方法是不是销售
if("saleProduct".equals(method.getName())){
return method.invoke(producer,money*0.8f);
}
return returnValue;
}
});
proxyProducer.saleProduct(10000f);
}
- 2.基于子类的动态代理
/*
* 模拟一个消费者*/
public class Client {
public static void main(String[] args) {
final Producer producer = new Producer();
producer.saleProduct(10000f);
/*
* 动态代理:
* 特点: 字节码随用随创建,随用随加载
* 作用:不修改源码的基础上对方法增强
* 分类
* 基于接口的动态代理
* 基于子类的动态代理
* 基于子类的动态代理:
* 涉及的类:Enhancer
* 提供者:第三方cglib库
* 如何创建代理对象:
* 使用Enhancer类中的create方法
* 创建代理对象的要求:
* 被代理类不能是最终类
* newProxyInstance方法的参数:
* Class:字节码
* 它是用于指定被代理对象的字节码
* Callback:用于提供增强的代码
* 它是让我们写如何代理。我们一般都是一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。
* 此接口的实现类都是谁用谁写。
* 我们一般写的都是该接口的子接口实现类:MethodInterceptor
* */
Producer cglibProducer = (Producer) Enhancer.create(producer.getClass(), new MethodInterceptor() {
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)
throws Throwable {
//提供增强的代码
Object returnValue = null;
//1.获取方法执行的参数
Float money = (Float) objects[0];
//2.判断当前方法是不是销售
if("saleProduct".equals(method.getName())){
return method.invoke(producer,money*0.8f);
}
return returnValue;
}
});
cglibProducer.saleProduct(12000f);
}