四种控制事务的方法
第一种
在DAO层控制事务
新建项目tx1
1.导入所需jar包
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.新建com.view包,模拟客户端调用action
package com.view;
import com.service.BusinessService;
import com.service.impl.BusinessServiceImpl;
public class Client {
public static void main(String[] args) {
BusinessService s =
new BusinessServiceImpl();
s.transfer(
"aaa",
"bbb",
100);
}
}
3.新建com.service包,写业务接口
package com.service;
public interface BusinessService {
/**
* 模拟转账
* @param from 转出的账户
* @param to 目标账户
* @param money 交易金额
*/
void transfer(String from, String to,
float money);
}
4.新建com.service.impl包,实现业务接口
package com.service.impl;
import java.sql.Connection;
import com.dao.AccountDao;
import com.dao.impl.AccountDaoImpl;
import com.service.BusinessService;
import com.utils.DBCPUtil;
public class BusinessServiceImpl implements BusinessService {
private AccountDao dao =
new AccountDaoImpl();
@Override
public void transfer(String from, String to,
float money) {
dao.transfer(from, to, money);
}
}
5.新建com.dao包,写数据接口DAO
package com.dao;
public interface AccountDao {
/**
* 转账,这里有点牵扯到业务的意思
* @param from
* @param to
* @param money
*/
void transfer(String from, String to,
float money);
}
6.新建com.dao.impl,写数据接口DAO的实现
package com.dao.impl;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.commons.dbutils.QueryRunner;
import com.dao.AccountDao;
import com.utils.DBCPUtil;
public class AccountDaoImpl implements AccountDao {
private QueryRunner qr =
new QueryRunner();
@Override
public void transfer(String from, String to,
float money) {
Connection conn =
null;
try {
conn =DBCPUtil.getConnection();
conn.setAutoCommit(
false);
qr.update(conn,
"update account set money=money-? where name=?",money,from);
qr.update(conn,
"update account set money=money+? where name=?",money,to);
}
catch (Exception e) {
if(conn!=
null){
try {
conn.rollback();
}
catch (SQLException e1) {
e1.printStackTrace();
}
}
}
finally{
if(conn!=
null){
try {
conn.commit();
conn.close();
}
catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
7.工具类
package com.utils;
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);
}
}
}
8.dbconfig.properties
driverClassName=com.mysql.jdbc.Driver
url=jdbc\:mysql\://localhost\:3306/jdbc
username=root
password=19941119liu
initialSize=10
maxActive=50
maxIdle=20
minIdle=5
maxWait=60000
connectionProperties=useUnicode=true;characterEncoding=utf8
defaultAutoCommit=true
defaultReadOnly=
defaultTransactionIsolation=REPEATABLE_READ
第二种
业务层控制事务
拷贝tx1项目到tx2
1.新建com.domain包,描述实体Account
package com.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;
}
}
2.修改AccountDao.java
AccountDao不在涉及到业务,只做crud操作
package com.dao;
import com.domain.Account;
public interface AccountDao {
/**
* 根据户名查询账户
* @param accountName
* @return
*/
Account findByName(String accountName);
/**
* 更新账户
* @param account
*/
void updateAccount(Account account);
}
3.修改dao的实现
package com.dao.impl;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import com.dao.AccountDao;
import com.domain.Account;
import com.utils.DBCPUtil;
public class AccountDaoImpl implements AccountDao {
private QueryRunner qr =
new QueryRunner();
private Connection conn;
public AccountDaoImpl(Connection conn){
this.conn = conn;
}
@Override
public Account
findByName(String accountName) {
try {
return qr.query(conn,
"select * from account where name=?",
new BeanHandler<Account>(Account.class),accountName);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void updateAccount(Account account) {
try {
qr.update(conn,
"update account set money=? where id=?",account.getMoney(),account.getId());
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
}
4.业务接口不变,只需修改业务实现
package com.service.impl;
import java.sql.Connection;
import java.sql.SQLException;
import com.dao.AccountDao;
import com.dao.impl.AccountDaoImpl;
import com.domain.Account;
import com.service.BusinessService;
import com.utils.DBCPUtil;
public class BusinessServiceImpl implements BusinessService {
@Override
public void transfer(String from, String to,
float money) {
Connection conn =
null;
try {
conn = DBCPUtil.getConnection();
conn.setAutoCommit(
false);
AccountDao dao =
new AccountDaoImpl(conn);
Account fromAccount = dao.findByName(from);
Account toAccount = dao.findByName(to);
fromAccount.setMoney(fromAccount.getMoney() - money);
toAccount.setMoney(toAccount.getMoney() + money);
dao.updateAccount(fromAccount);
dao.updateAccount(toAccount);
}
catch (Exception e) {
if (conn !=
null) {
try {
conn.rollback();
}
catch (SQLException e1) {
e1.printStackTrace();
}
}
e.printStackTrace();
}
finally {
if (conn !=
null) {
try {
conn.commit();
conn.close();
}
catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
第三种
抽取工具类,封装与事务有关的方法
拷贝tx2项目到tx3项目
1.在com.utils包中新建TransactionManager.java
package com.utils;
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(){
Connection conn = getConnection();
try {
conn.rollback();
}
catch (SQLException e) {
e.printStackTrace();
}
}
public static void release(){
try {
Connection conn = getConnection();
conn.close();
tl.remove();
}
catch (SQLException e) {
e.printStackTrace();
}
}
public static void commit(){
try {
Connection conn = getConnection();
conn.commit();
}
catch (SQLException e) {
e.printStackTrace();
}
}
}
3.重写业务的实现
package com.service.impl;
import java.sql.Connection;
import java.sql.SQLException;
import com.dao.AccountDao;
import com.dao.impl.AccountDaoImpl;
import com.domain.Account;
import com.service.BusinessService;
import com.utils.DBCPUtil;
import com.utils.TransactionManager;
public class BusinessServiceImpl implements BusinessService {
private AccountDao dao =
new AccountDaoImpl();
@Override
public void transfer(String from, String to,
float money) {
try {
TransactionManager.startTransaction();
Account sAccount = dao.findByName(from);
Account tAccount = dao.findByName(to);
sAccount.setMoney(sAccount.getMoney() - money);
tAccount.setMoney(tAccount.getMoney() + money);
dao.updateAccount(sAccount);
dao.updateAccount(tAccount);
}
catch (Exception e) {
TransactionManager.rollback();
}
finally{
TransactionManager.commit();
TransactionManager.release();
}
}
}
第四种
AOP控制事务
通过AOP拦截业务方法,给业务方法加上事务的方法
1.首先修改业务方法的实现,修改transfer()方法
package com.service.impl;
import java.sql.Connection;
import java.sql.SQLException;
import com.dao.AccountDao;
import com.dao.impl.AccountDaoImpl;
import com.domain.Account;
import com.service.BusinessService;
import com.utils.DBCPUtil;
import com.utils.TransactionManager;
public class BusinessServiceImpl implements BusinessService {
private AccountDao dao =
new AccountDaoImpl();
@Override
public void transfer(String from, String to,
float money) {
Account sAccount = dao.findByName(from);
Account tAccount = dao.findByName(to);
sAccount.setMoney(sAccount.getMoney() - money);
tAccount.setMoney(tAccount.getMoney() + money);
dao.updateAccount(sAccount);
dao.updateAccount(tAccount);
}
}
2.客户端再调用的时候,调用的是工厂产生的代理对象,代理对象的方法结合了业务方法和事务方法
package com.utils;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import com.service.BusinessService;
import com.service.impl.BusinessServiceImpl;
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() {
@Override
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;
}
}
3.客户端通过工厂拿到业务实例
package com.view;
import com.service.BusinessService;
import com.service.impl.BusinessServiceImpl;
import com.utils.BeanFactory;
public class Client {
public static void main(String[] args) {
BusinessService s = BeanFactory.getBusinessService();
s.transfer(
"aaa",
"bbb",
100);
}
}