import java.sql.Connection;
import java.sql.DriverManager;
public class DbUtil {
/**
* 獲取數據庫連接,如果使用其他數據庫,修改這裏就可以了。
* @return
*/
public static Connection getConnection() {
Connection conn = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/st", "root", "");
}
catch(Exception e) {
e.printStackTrace();
}
return conn;
}
}
import java.sql.Connection;
public interface IDb {
/**
* 設置數據庫連接
* @param conn
*/
void setConnection(Connection conn);
/**
* 獲取數據庫連接。
* 如果沒有設置返回null。
* @return
* @throws Exception
*/
Connection getConnection();
/**
* 釋放數據庫連接
* @param conn
* @throws Exception
*/
void closeConnection();
}
import java.sql.Connection;
import java.sql.Statement;
public class DbImpl implements IDb {
private Connection conn;
@Override
public void closeConnection() {
try {
if (conn != null) conn.close();
conn = null;
System.out.println("close conn");
}
catch(Exception e) {
e.printStackTrace();
}
}
@Override
public Connection getConnection() {
return conn;
}
@Override
public void setConnection(Connection conn) {
this.conn = conn;
System.out.println("set conn");
}
protected int executeNonQuery(String sql) throws Exception {
System.out.println("executeNonQuery begin:" + sql);
Statement stmt = null;
int result = 0;
try {
stmt = getConnection().createStatement();
result = stmt.executeUpdate(sql);
}
catch(Exception e) {
throw e;
}
finally {
if (stmt != null) stmt.close();
}
System.out.println("executeNonQuery complete:" + sql);
return result;
}
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 被註解的方法可以自動獲取數據庫連接並開啓事務。
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Transactional {
boolean autoCommit() default false;
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.sql.Connection;
import demo.dynamicproxy.annotation.Transactional;
/**
* 自動處理數據庫連接、事務的調用處理器
*/
public class TransactionalInvocationHandler implements InvocationHandler {
private Object target;
private IDb db;
/**
* 構造方法
* @param target
*/
public TransactionalInvocationHandler(Object target) {
this.target = target;
this.db = (IDb) target;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("method invoke begin:" + method.getName());
Object result = null;
boolean isNeedTransaction = false;
boolean isAutoCommit = false;
if (method.isAnnotationPresent(Transactional.class)) {
isNeedTransaction = true;
isAutoCommit = method.getAnnotation(Transactional.class).autoCommit();
}
boolean isLocalOpen = false;
boolean rollback = false;
Connection conn = db.getConnection();
System.out.println("isNeedTransaction:" + isNeedTransaction);
System.out.println("isAutoCommit:" + isAutoCommit);
System.out.println("isLocalOpen:" + isLocalOpen);
try {
if (isNeedTransaction) {
if (conn == null) {
isLocalOpen = true;
try {
conn = DbUtil.getConnection();
if (conn == null) throw new Exception("數據庫連接獲取錯誤");
conn.setAutoCommit(isAutoCommit);
}
catch (Exception e) {
throw e;
}
db.setConnection(conn);
}
}
result = method.invoke(this.target, args);
}
catch(Exception e) {
rollback = true;
e.printStackTrace();
throw e;
}
finally {
if (conn != null && isLocalOpen) {
if (!isAutoCommit) {
if (rollback) conn.rollback();
else conn.commit();
}
db.closeConnection();
}
}
System.out.println("method invoke complete:" + method.getName());
return result;
}
}
import java.lang.reflect.Proxy;
public class DefaultProxyFactory {
@SuppressWarnings("unchecked")
public static <T> T createProxy(T target) throws Exception {
if (!(target instanceof IDb)) throw new Exception("target must be instance of IDb");
ClassLoader classLoader = target.getClass().getClassLoader();
Class<?>[] interfaces = target.getClass().getInterfaces();
TransactionalInvocationHandler handler = new TransactionalInvocationHandler(target);
return (T) Proxy.newProxyInstance(classLoader, interfaces, handler);
}
}
import demo.dynamicproxy.annotation.Transactional;
public interface IDml {
void insert() throws Exception;
void update() throws Exception;
void delete() throws Exception;
void select() throws Exception;
@Transactional(autoCommit=false)
void execute() throws Exception;
}
import java.sql.ResultSet;
import java.sql.Statement;
import demo.dynamicproxy.DbImpl;
import demo.dynamicproxy.DefaultProxyFactory;
public class Dml extends DbImpl implements IDml {
@Override
public void delete() throws Exception{
executeNonQuery("delete from t where id=2");
System.out.println("delete 2");
}
@Override
public void execute() throws Exception{
System.out.println("begin");
insert();
update();
//if (true) throw new Exception("an error"); //此處測試異常
select();
delete();
}
@Override
public void insert() throws Exception{
executeNonQuery("insert into t(id) values(1)");
System.out.println("insert 1");
}
@Override
public void select() throws Exception{
Statement stmt = null;
ResultSet rs = null;
try {
stmt = getConnection().createStatement();
rs = stmt.executeQuery("select id from t");
while (rs.next()) {
System.out.println("select :" + rs.getString("ID"));
}
}
catch(Exception e) {
throw e;
}
finally {
if (rs != null) rs.close();
if (stmt != null) stmt.close();
}
}
@Override
public void update() throws Exception{
executeNonQuery("update t set id=2 where id=1");
System.out.println("update 2");
}
public static void main(String[] args) {
try {
Dml dmlImpl = new Dml();
IDml dml= DefaultProxyFactory.createProxy(dmlImpl);
dml.execute();
Thread.sleep(20000); //延遲程序退出,可以查看數據庫連接有沒有釋放
System.out.println("over");
}
catch(Exception e) {
e.printStackTrace();
}
}
}