您的位置:首页 > 编程语言 > Java开发

2014-07-16 Java Web的学习(13)-----DBUtil&基于DBUtil的事务处理(动态代理AOP)

2015-04-10 13:16 459 查看
一、数据库元数据信息

具体来说指的是数据库,表等定义信息(DDL信息).

1.数据库的元数据:

DatabaseMetaData metaData = Connection.getMetaData();

这个对象表示该Connection
对象所连接的数据库的元数据,元数据包括关于数据库的表、受支持的SQL 语法、存储过程、此连接功能等等的信息.至于对象方法,就自己查看JDK API.其中里面大部分都是Get方法.

2.
ParameterMetaData metaData=stmt.getParameterMetaData();

一个
ParameterMetaData
对象,它包含有关此
PreparedStatement
对象的每个参数标记的编号、类型和属性的信息.

3.
ResultSetMetaData rsmd = rs.getMetaData();

可用于获取关于
ResultSet
对象中列的类型和属性信息的对象
二、编写自己的JDBC框架

数据库元数据有什么作用?就是让我们用来简单封装JDBC.在JDBC中一系列的操作中,都有很多相同的步骤,不同只是SQL语句和参数.而DQL语句可能存在结果.而数据库的操作语言都是执行stmt.executeUpdate.
而查询语言就要稍微复杂一点.分为返回结果ResultSet res无非封装Bean或者是List<Bean>中.封装时使用ResultSetHandle接口处理器.而不同结果集实现处理器是不同.BeanHandle实现ResultSetHandle接口用来处理封装一条记录.BeanListHandle实现ResultHandle用来封装多条记录.这就是所谓的策略模式.最后上代码:
/**

* 封装JDBC中的update,insert,delete方法.

*
@param
sql

*
@param
params

*/

public
void
update(String sql,Object...params){

try
{

Connection conn =
dataSource
.getConnection();

PreparedStatement stmt = conn.prepareStatement(sql);

ParameterMetaData metaData = stmt.getParameterMetaData();

int
paramCount=metaData.getParameterCount();

if
(paramCount>0){

if
(params==
null
|| params.
length
<=0){

throw
new
IllegalArgumentException(
"参数不匹配."
);

}

if
(paramCount!=params.
length
){

throw
new
IllegalArgumentException(
"参数不匹配."
);

}

for
(
int
i=0;i<paramCount;i++){

//设置参数

stmt.setObject(i+1, params);

}

}

stmt.executeUpdate();

}
catch
(SQLException e) {

throw
new
RuntimeException(e);

}

}

/**

* 封装JDBC中的Query方法

*/

public
Object query(String sql,ResultSetHandler rsh,Object...params){

try
{

Connection conn =
dataSource
.getConnection();

PreparedStatement stmt = conn.prepareStatement(sql);

ParameterMetaData metaData = stmt.getParameterMetaData();

int
paramCount=metaData.getParameterCount();

if
(paramCount>0){

if
(params==
null
|| params.
length
<=0){

throw
new
IllegalArgumentException(
"参数不匹配."
);

}

if
(paramCount!=params.
length
){

throw
new
IllegalArgumentException(
"参数不匹配."
);

}

for
(
int
i=0;i<paramCount;i++){

stmt.setObject(i+1, params[i]);

}

}

ResultSet rs=stmt.executeQuery();

//怎么讲结果集封装到JavaBean中.

Object result = rsh.handle(rs);

return
result;

}
catch
(SQLException e) {

throw
new
RuntimeException(e);

}

}

public
interface
ResultSetHandler {

Object handle(ResultSet rs);

}

两种处理器:











PS:列名和字段必须要求一致.目前还做不到自定义字段名和字段名的映射关系.

策略模式:图示
场景中的要素:三个妙计,一个锦囊,一个赵云,妙计是亮哥给的,妙计放在锦囊里,俗称就是锦囊妙计嘛,那赵云就是一个干活的人,从锦囊取出妙计,执行,然后获胜





三、开源框架DBUtil(简单封装JDBC)

了解DBUtil框架,主要熟悉它的不同处理器Handle.具体就不介绍啦,自己查看文档吧.

ArrayHandler

ArrayListHandler

*BeanHandler

*BeanListHandler

ColumnListHandler

KeyedHandler

MapHandler

MapListHandler

*
ScalarHandler

QueryRunner qr = new QueryRunner(数据源);

QueryRunner qr = new QueryRunner(); //与事务控制相关.
四、BDUtil在实际开发中事务的控制(已转账为案例)

1.Dao层对于事物的控制(一般不使用,只负责增删改查,不关注业务逻辑)

/**

* 在DButils中使用控制事务,使用同一Connection对象连接.

*/

private
QueryRunner
qr
=
new
QueryRunner();

@Override

public
void
transfer(String sourceName, String destName,
float
money) {

Connection conn =
null
;

try
{

conn = DBCPUtil.[i]getConnection();

conn.setAutoCommit(
false
);

qr
.update( conn,
"update account set money=money-? where name=?"
,
new
Object[] {

money, sourceName });

int
a = 1/0; //抛出异常

qr
.update( conn,
"update account set money=money+? where name=?"
,
new
Object[] {

money, destName });

conn.commit();

}
catch
(Exception e) {

throw
new
RuntimeException(e);

}
finally
{

if
(conn!=
null
){

try
{

/*放回数据库连接池*/

conn.close();

}
catch
(SQLException e) {

throw
new
RuntimeException(e);

}

conn=
null
;

}

}

}
2.Service层对于事物的处理(Service中抛出SQLException,如果Dao换成Hibernate实现的话.就会出现问题)

Dao层的设计Connection对象注入进来:





public
void
transfer(String sourceName, String destName,
float
money){

Connection conn =
null
;

try
{

conn = DBCPUtil. getConnection();

conn.setAutoCommit(
false
);

AccountDao dao =
new
AccountDaoImpl(conn);

Account source = dao.findAccountByName(sourceName);

Account dest = dao.findAccountByName(destName);

source.setMoney(source.getMoney()-money);

dest.setMoney(dest.getMoney()+money);

dao.updateAccount(source);

int
a=1/0;

dao.updateAccount(dest);

conn.commit();

}
catch
(SQLException e) {

throw
new
RuntimeException(e);

}
finally
{

if
(conn!=
null
){

try
{

conn.close();

}
catch
(SQLException e) {

e.printStackTrace();

}

}

}

}
3.通过ThreadLocal解决上面问题的事务处理
ThreadLocal,直译为“线程本地”或“本地线程”,如果你真的这么认为,那就错了!其实,它就是一个容器,用于存放线程的局部变量,我认为应该叫做 ThreadLocalVariable(线程局部变量)才对.

//模拟ThreadLocal public class ThreadLocal{ private Map<Runnable,Object> map = new HashMap<Runnable,Object>(); public void set(Object obj){ map.put(Thread.currentThread(),obj); } pulbic void remove(){ map.remove(Thread.currentThread()); } public Object get(){ return map.get(Thread.currentThread()); } } 以线程为Key,将某个变量实例存放在ThreadLocal中.ThreadLocal中实际上就是一个Map集合.所以称作线程局部变量.
编写一个控制事务的类:TransactionManager









public
void
transfer(String sourceName, String destName,
float
money) {

TransactionManager. startTransaction();

AccountDao dao =
new
AccountDaoImpl(TransactionManager.getConnection());

Account source = dao.findAccountByName(sourceName);

Account dest = dao.findAccountByName(destName);

source.setMoney(source.getMoney() - money);

dest.setMoney(dest.getMoney() + money);

dao.updateAccount(source);

int
a = 1 / 0;

dao.updateAccount(dest);

TransactionManager. commitTransaction();

TransactionManager. release();

}
4.通过动态代理更加细粒度的控制事务




BeanFactory.java
package com.itheima.utils;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import com.ithiema.service.AccountService;
import com.ithiema.service.impl.AccountServiceImpl;
public class BeanFactory {
/**
* 解耦.拦截
* @return AccountService
*/
public static AccountService getAccountServiceImpl(){
final AccountService service = new AccountServiceImpl();
AccountService proxy = (AccountService) Proxy.newProxyInstance(AccountService.class.getClassLoader()
, service.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if("transfer".equals(method.getName())){
try {
TransactionManager.startTransaction();
Object objValue = method.invoke(service, args);
TransactionManager.commitTransaction();
return objValue;
} catch (Exception e) {
TransactionManager.rollBackTransaction();
throw new RuntimeException(e);
} finally{
TransactionManager.release();
}
}else{
return method.invoke(service, args);
}
}
});
return proxy;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐