- 转账业务是一种事务,所以需要保证数据的安全性。在转账中途如果出现错误,需要将数据进行回滚。
- 本次示例用到了事务、ThreadLocal、动态代理等多个概念。
- 本次实例需要用到的包如下:
lib/c3p0-0.9.1.2.jar c3p0需要对应的配置文件:c3p0-config.xml,其中配置了数据库连接、连接池大小等参数
lib/commons-dbutils-1.4.jar
lib/mysql-connector-java-5.0.8-bin.jar
package test;
import service.AccountService;
import util.ObjectFactory;
public class TestTransfer {
public static void main(String[] args) throws Exception {
AccountService as = ObjectFactory.getAccountService();
as.transfer("aaa", "bbb", 100);
}
}
package service.impl;
import dao.AccountDao;
import dao.impl.AccountDaoImpl;
import domain.Account;
import service.AccountService;
public class AccountServiceImpl implements AccountService {
public void transfer(String fromname, String toname, double money) throws Exception {
AccountDao ad = new AccountDaoImpl();
Account fromAccount = ad.findAccountByName(fromname);
Account toAccount = ad.findAccountByName(toname);
fromAccount.setMoney(fromAccount.getMoney() - money);
toAccount.setMoney(toAccount.getMoney() + money);
ad.updateAccout(fromAccount);
ad.updateAccout(toAccount);
}
}
package dao.impl;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import dao.AccountDao;
import domain.Account;
import util.ManagerThreadLocal;
public class AccountDaoImpl implements AccountDao {
public void updateAccout(Account account) throws Exception {
QueryRunner qr = new QueryRunner();
qr.update(ManagerThreadLocal.getConnection(), "update account set money=? where name=?", account.getMoney(), account.getName());
}
public Account findAccountByName(String name) throws Exception {
QueryRunner qr = new QueryRunner();
return qr.query(ManagerThreadLocal.getConnection(), "select * from account where name=?", new BeanHandler<Account>(Account.class), name);
}
}
- 下面展示管理连接和事务的工具类,为低层数据库交互类和代理对象工厂类提供支持
package util;
import java.sql.Connection;
import java.sql.SQLException;
public class ManagerThreadLocal {
private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
public static Connection getConnection() {
Connection conn = tl.get();
if (conn == null) {
conn = C3P0Util.getConnection();
tl.set(conn);
}
return conn;
}
public static void startTransacation() {
try {
Connection conn = getConnection();
conn.setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void commit() {
try {
getConnection().commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void rollback() {
try {
getConnection().rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void close() {
try {
getConnection().close();
tl.remove();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
- 下面展示提供数据库连接的工具类,为管理连接的工具类提供支持
package util;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class C3P0Util {
private static DataSource dataSource = new ComboPooledDataSource();
public static DataSource getDataSource() {
return dataSource;
}
public static Connection getConnection() {
try {
return dataSource.getConnection();
} catch (SQLException e) {
throw new RuntimeException("服务器错误");
}
}
}
package util;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import service.AccountService;
import service.impl.AccountServiceImpl;
public class ObjectFactory {
public static AccountService getAccountService() {
final AccountService as = new AccountServiceImpl();
AccountService proxy = (AccountService) Proxy.newProxyInstance(as.getClass().getClassLoader(), as.getClass().getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke = null;
try {
ManagerThreadLocal.startTransacation();
invoke = method.invoke(as, args);
ManagerThreadLocal.commit();
} catch (Exception e) {
try {
ManagerThreadLocal.rollback();
} catch (Exception e1) {
e1.printStackTrace();
}
} finally {
try {
ManagerThreadLocal.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return invoke;
}
});
return proxy;
}
}