採用DBUtil框架實現AOP(面向切面程式設計)對事務的處理
阿新 • • 發佈:2019-02-16
專案中個檔案的結構:
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);