1. 程式人生 > >採用DBUtil框架實現AOP(面向切面程式設計)對事務的處理

採用DBUtil框架實現AOP(面向切面程式設計)對事務的處理

專案中個檔案的結構:
這裡寫圖片描述
1。導包:
commons-dbcp-1.4.jar
commons-dbutils-1.4.jar
commons-pool-1.5.6.jar
mysql-connector-java-5.0.8-bin.jar
2.dbcpconfig.properties配置檔案:

#\u8FDE\u63A5\u8BBE\u7F6E
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/day18
username=root
password=admin

#<!-- \u521D\u
59CB\u5316\u8FDE\u63A5 --> initialSize=10 #\u6700\u5927\u8FDE\u63A5\u6570\u91CF maxActive=50 #<!-- \u6700\u5927\u7A7A\u95F2\u8FDE\u63A5 --> maxIdle=20 #<!-- \u6700\u5C0F\u7A7A\u95F2\u8FDE\u63A5 --> minIdle=5 #<!-- \u8D85\u65F6\u7B49\u5F85\u65F6\u95F4\u4EE5\u6BEB\u79D2\u4E3A\u5355\u4F4D 6000\u
6BEB\u79D2/1000\u7B49\u4E8E60\u79D2 --> maxWait=60000 #JDBC\u9A71\u52A8\u5EFA\u7ACB\u8FDE\u63A5\u65F6\u9644\u5E26\u7684\u8FDE\u63A5\u5C5E\u6027\u5C5E\u6027\u7684\u683C\u5F0F\u5FC5\u987B\u4E3A\u8FD9\u6837\uFF1A[\u5C5E\u6027\u540D=property;] #\u6CE8\u610F\uFF1A"user" \u4E0E "password" \u4E24\u4E2A\u5C5E\u6027\u4F1A\u
88AB\u660E\u786E\u5730\u4F20\u9012\uFF0C\u56E0\u6B64\u8FD9\u91CC\u4E0D\u9700\u8981\u5305\u542B\u4ED6\u4EEC\u3002 connectionProperties=useUnicode=true;characterEncoding=utf8 #\u6307\u5B9A\u7531\u8FDE\u63A5\u6C60\u6240\u521B\u5EFA\u7684\u8FDE\u63A5\u7684\u81EA\u52A8\u63D0\u4EA4\uFF08auto-commit\uFF09\u72B6\u6001\u3002 defaultAutoCommit=true #driver default \u6307\u5B9A\u7531\u8FDE\u63A5\u6C60\u6240\u521B\u5EFA\u7684\u8FDE\u63A5\u7684\u53EA\u8BFB\uFF08read-only\uFF09\u72B6\u6001\u3002 #\u5982\u679C\u6CA1\u6709\u8BBE\u7F6E\u8BE5\u503C\uFF0C\u5219\u201CsetReadOnly\u201D\u65B9\u6CD5\u5C06\u4E0D\u88AB\u8C03\u7528\u3002\uFF08\u67D0\u4E9B\u9A71\u52A8\u5E76\u4E0D\u652F\u6301\u53EA\u8BFB\u6A21\u5F0F\uFF0C\u5982\uFF1AInformix\uFF09 defaultReadOnly= #driver default \u6307\u5B9A\u7531\u8FDE\u63A5\u6C60\u6240\u521B\u5EFA\u7684\u8FDE\u63A5\u7684\u4E8B\u52A1\u7EA7\u522B\uFF08TransactionIsolation\uFF09\u3002 #\u53EF\u7528\u503C\u4E3A\u4E0B\u5217\u4E4B\u4E00\uFF1A\uFF08\u8BE6\u60C5\u53EF\u89C1javadoc\u3002\uFF09NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE defaultTransactionIsolation=REPEATABLE_READ

3。測試類Client.java檔案:

package com.itheima.view;

import com.itheima.service.BusinessService;
import com.itheima.util.BeanFactory;

public class Client {

    public static void main(String[] args) {
        BusinessService s = BeanFactory.getBusinessService();
        s.transfer("aaa", "bbb", 100);
    }

}

4。service介面(BusinessService.java檔案):

package com.itheima.service;

public interface BusinessService {
    /**
     * 轉賬
     * @param sourceAccountName 轉出賬戶
     * @param targetAccontName 轉入賬戶
     * @param money 交易金額
     */
    void transfer(String sourceAccountName,String targetAccontName,float money);
}

5。service介面的實現類(BusinessServiceImpl):

package com.itheima.service.impl;


import com.itheima.dao.AccountDao;
import com.itheima.dao.impl.AccountDaoImpl;
import com.itheima.domain.Account;
import com.itheima.service.BusinessService;

//業務層控制事務
public class BusinessServiceImpl implements BusinessService {
    private AccountDao dao = new AccountDaoImpl();
    public void transfer(String sourceAccountName, String targetAccontName,
            float money) {
        Account sAccount = dao.findByName(sourceAccountName);
        Account tAccount = dao.findByName(targetAccontName);
        sAccount.setMoney(sAccount.getMoney() - money);
        tAccount.setMoney(tAccount.getMoney() + money);
        dao.updateAcount(sAccount);
        int i=1/0;
        dao.updateAcount(tAccount);

    }

}

6。Dao介面(AccountDao.java檔案):

package com.itheima.dao;

import com.itheima.domain.Account;

//DAO層:不能牽扯到任何業務有關的邏輯。
//DAO:只負責CRUD
public interface AccountDao {
    /**
     * 根據戶名查詢賬戶
     * @param accountName
     * @return
     */
    Account findByName(String accountName);
    /**
     * 更新賬戶
     * @param account
     */
    void updateAcount(Account account);
}

7。Dao介面的實現(AccountDaoImpl):

package com.itheima.dao.impl;

import java.sql.SQLException;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;

import com.itheima.dao.AccountDao;
import com.itheima.domain.Account;
import com.itheima.util.TransactionManager;

public class AccountDaoImpl implements AccountDao {
    private QueryRunner qr = new QueryRunner();

    public Account findByName(String accountName) {
        try {
            return qr.query(TransactionManager.getConnection(),"select * from account where name=?", new BeanHandler<Account>(Account.class),accountName);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    public void updateAcount(Account account) {
        try {
            qr.update(TransactionManager.getConnection(),"update account set money=? where id=?", account.getMoney(),account.getId());
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }


}

8。模型(Account.java):

package com.itheima.domain;

public class Account {
    private int id;
    private String name;
    private float money;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public float getMoney() {
        return money;
    }
    public void setMoney(float money) {
        this.money = money;
    }

}

9.工具類:
DBCPUtil.java檔案:

package com.itheima.util;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSourceFactory;

public class DBCPUtil {
    private static DataSource dataSource;
    static{
        try {
            InputStream in = DBCPUtil.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
            Properties props = new Properties();
            props.load(in);
            dataSource = BasicDataSourceFactory.createDataSource(props);
        } catch (Exception e) {
            throw new ExceptionInInitializerError(e);
        }
    }

    public static DataSource getDataSource(){
        return dataSource;
    }

    public static Connection getConnection(){
        try {
            return dataSource.getConnection();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

BeanFactory.java檔案:

package com.itheima.util;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import com.itheima.service.BusinessService;
import com.itheima.service.impl.BusinessServiceImpl;
//AOP
public class BeanFactory {
    public static BusinessService getBusinessService(){
        final BusinessService s = new BusinessServiceImpl();

        BusinessService proxyS = (BusinessService)Proxy.newProxyInstance(s.getClass().getClassLoader(), 
                s.getClass().getInterfaces(), 
                new InvocationHandler() {
                    public Object invoke(Object proxy, Method method, Object[] args)
                            throws Throwable {
                        try {
                            TransactionManager.startTransaction();
                            Object rtValue = method.invoke(s, args);
                            return rtValue;
                        } catch (Exception e) {
                            TransactionManager.rollback();
                            throw new RuntimeException(e);
                        } finally {
                            TransactionManager.commit();
                            TransactionManager.release();
                        }
                    }
                });

        return proxyS;
    }
}

TransactionManager.java檔案:

package com.itheima.util;

import java.sql.Connection;
import java.sql.SQLException;
//封裝了所有與事務有關的方法
public class TransactionManager {
    private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
    public static Connection getConnection(){
        Connection conn = tl.get();
        if(conn==null){//從當前執行緒中獲取連結
            conn = DBCPUtil.getConnection();
            tl.set(conn);
        }
        return conn;
    }
    public static void startTransaction(){
        try {
            Connection conn = getConnection();
            conn.setAutoCommit(false);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    public static void rollback(){
        try {
            Connection conn = getConnection();
            conn.rollback();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    public static void commit(){
        try {
            Connection conn = getConnection();
            conn.commit();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    public static void release(){
        try {
            Connection conn = getConnection();
            conn.close();
            tl.remove();//從當前執行緒中解綁。  與伺服器實現有關:伺服器採用執行緒池。
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

10。資料庫的sql語句(account.sql):

create table account (
    id int primary key auto_increment,
    name varchar(40),
    money float
)character set utf8 collate utf8_general_ci;

insert into account(name,money)values('aaa',1000);
insert into account(name,money)values('bbb',1000);