java中数据库事务和代理(初级)

1.事务

      引入案例:银行转账  A账户给B账户转账    如果转账中出现异常,事务就必须停止,且回滚。也就是转账过程,要么全部成功,要么全部失败,所以必须放在同一个事务

     然而,Connection默认是事务自动提交的,要在同一个事务中操作,就必须多个关于数据的操作必须是同一个连接

     保证操作中是同一个Connection就需要设置ThreadLocal操作

结构:

     在此,我把数据的连接包装在一个类中,JdbcUtil,db.properties   如下:

private static Properties prop = new Properties();
	private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();//code1
	static{
		try {
			prop.load(JdbcUtil.class.getResourceAsStream("/db.properties"));
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
	public static Connection getConnection(){
		Connection connection = tl.get();//code2
		try {
			if (connection==null) {
				Class.forName(prop.getProperty("jdbc.driverClass"));
				connection = DriverManager.getConnection(prop.getProperty("jdbc.url"),prop.getProperty("jdbc.user"),prop.getProperty("jdbc.pass"));
				tl.set(connection);//code3
			}
			
			return connection;
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
			return null;
		}
		
	}
	public static void close(Statement statement,ResultSet rs){
		if (rs!=null) {
			try {
				rs.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		if (statement!=null) {
			try {
				statement.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	/**
	 * 业务按成后 连接才能关闭
	 * <p>Title: closeConnection</p>  
	 * <p>Description: </p>
	 */
	public static void closeConnection(){
		Connection connection = tl.get();
		if(connection!=null){
			try {
				connection.close();
				tl.remove();//code4
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
jdbc.driverClass=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@localhost:1521:ORCL
jdbc.user=scott
jdbc.pass=0804

Account.java

public class Account {

	private int id;
	private int money;
	private String name;
	
	public Account() {
		// TODO Auto-generated constructor stub
	}
	public Account(int id, int money, String name) {
		super();
		this.id = id;
		this.money = money;
		this.name = name;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public int getMoney() {
		return money;
	}
	public void setMoney(int money) {
		this.money = money;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public String toString() {
		return "Account [id=" + id + ", money=" + money + ", name=" + name + "]";
	}
	
}

AccountService.java  接口类

public interface AccountService {

	public void insertAccount(Account account);
	public void updateAccount(Account account);
	public List<Account>getAll();
}

AccountServiceImpl.java实现类

public class AccountServiceImpl implements AccountService{

	@Override
	public void insertAccount(Account account){
		System.out.println("插入数据");
		
	}
	
	@Override
	public void updateAccount(Account account){
		System.out.println("更新数据");
		
	}
	@Override
	public List<Account>getAll(){
		System.out.println("获取数据");
		return null;
	}
}

因为是在同一线程中,Connection就不能随时close,否则,后面的操作将无法进行,所以,要单独写一个关闭Connection的方法,需要时再关闭

2.代理  

为了避免在每个方法中都要写事务处理的问题,我们引入了代理,这样做就可以把dao和事务处理分离,开发人员做到各司其职,也就是AOP 面向方面的编程

   代理分为静态代理和动态代理

   2.1 静态代理

      a. 创建一个代理类,实现与业务实现同一个接口,并且把代理类的实例作为自己的成员

AccountProxy.java 静态代理类

public class AccountProxy implements AccountService{

	AccountServiceImpl asi;
	public void setAsi(AccountServiceImpl asi) {
		this.asi = asi;
	}
	@Override
	public void insertAccount(Account account) {
		// TODO Auto-generated method stub
		System.out.println("开启事务");
		asi.insertAccount(account);
		System.out.println("提交事务,有问题就回滚事务");
		
	}

	@Override
	public void updateAccount(Account account) {
		// TODO Auto-generated method stub
		System.out.println("开启事务");
		asi.updateAccount(account);
		System.out.println("提交事务,有问题就回滚事务");
		
	}

	@Override
	public List<Account> getAll() {
		// TODO Auto-generated method stub
		System.out.println("开启事务");
		asi.getAll();
		System.out.println("提交事务,有问题就回滚事务");
		return null;
	}

}

测试代码

public class Demo1 {

	public static void main(String[] args) {
		AccountProxy ap = new AccountProxy();
		AccountServiceImpl asi = new AccountServiceImpl();
		ap.setAsi(asi);
		ap.insertAccount(null);
		ap.updateAccount(null);
	}
}

输出结果:

静态代理缺点:

要做的辅助操作(事务,日志等)在每个业务方法中都需要进行调用,为了解决这个问题,我们引入动态代理

a. 动态代理处理器 必须实现 java.lang.reflect.InvocationHandle接口

b. 把目标对象(要生成代理的对象)作为成员

c. 实现invoke方法 该方法会拦截所有 的目标对象的方法 d

d. 产生代理对象,可以直接利用代理处理器,也可以单独写一个类

ProxyFactoryBean.java 动态代理类

public class ProxyFactoryBean implements InvocationHandler {

	private Object target;//代理的目标对象-->调用目标对象的任何方法都会被invoke方法拦截
	/*public void setTarget(Object target) {
		this.target = target;
	}*/
	public ProxyFactoryBean(Object object) {
		// TODO Auto-generated constructor stub
		this.target = object;
	}
	
	/**
	 * 参数method 方法拦截后,拦截的目标对象的方法
	 * args就是方法的参数
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("开启事务");
		method.invoke(target, args);
		System.out.println("提交事务,有问题就回滚事务");
		
		return null;
	}
	
	public Object getProxy(){
		return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
	}
}

测试代码

public class ProxyDemo2 {

	public static void main(String[] args) {
		AccountServiceImpl aServiceImpl = new AccountServiceImpl();//目标对象
		//代理处理器,代理工厂
		ProxyFactoryBean pfb = new ProxyFactoryBean(aServiceImpl);
		//pfb.setTarget(aServiceImpl);
		AccountService as = (AccountService)pfb.getProxy();
		as.insertAccount(null);
	}
	
	
}

测试结果

动态代理的缺点:

目标对象的所有方法都会被拦截处理

处理办法:

不过我们可以根据方法对象来控制,此处就不具体说明

 

 

永远不要停止思考...

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值