开发者学堂课程【DAO 开发实战业务分析:数据库连接控制加强】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/399/detail/5171
数据库连接控制加强
内容介绍:
一、简要介绍
二、步骤
三、总结
一、简要介绍
在整个 DAO 设计模式之中可以发现数据库的连接与连接控制都是放在了业务层之中完成,而后在实例化数据层对象的时候往往要有一个 Connection 接口对象。
二、步骤
· 观察 DAO 接口实现类,MessageDAOImpl :首先在此实现类之中,其代码有一个关键性的问题。
p
ublic MemberDAOImpl(Connection conn) {
this.conn = conn ;
}
通过观察,可发现在这个实现类上会发现需要一个明确的 Connection 作为构造的参数。
在工厂设计方法里面还需要使用 Constructor 明确地去进行
指定参数构造的调用。如果是真实的工厂最好运用的是无参。
public
static
<
T
>
T
get
I
nstance(Class
<
T
>
cls,Connection
)
{
try
{
C
onstructor
<
T
>
cons
=
cls.
getCon
structor
(
Connection
.class
)
;
return cons.newInstance(conn) ;
} catch (Exception e) {
e.printStackTrace();
}
在整个 DAOFactory 的设计开发过程中,很少关注 Constructor,但现在必须去关注,因为需要得到一个明确的并且具备有 Connection 接口对象的操作。
· 既然 Connection 是整个操作的关键,如果没有 Connection 对象,整个的项目将无法运行,同时程序一定是多线程的模式来进行处理的,那么就必须考虑到每一个线程都可能有自己的 Connection 对象,所以现在最好的做法是使用 ThreadLocal 来实现 Connection 对象处理操作。真实的情况之中建议 DAO 的工厂类实现应该如下所示:
p
ackage cn.mldn.oracle.factory;
/**
* 取得D
AO
接口的工厂类
* @
author
mldn
*
/
public
class
DAOF
actory
{
private
DAOF
actory(){
}
;
/
/
为了不实现实例化对象
/**
* 定义D
AO
接口的对象取得
* @
param
cls
子类的Class对象
* @
return
一个接口的实例化对象
*/
public
static
<
T
>
T
get
I
nstance(Class
<
T
>
cls){
try
{
return c
ls
.newInstance() ;
} catch (Exception e) {
e.printStackTrace();
}
return
null
;
}
}
DAO 工厂最好的实现方法是通过 cls.newInstance() 来进行实例化而不是接收 connection,而采用反射的最大好处是没有实例化的同时整个过程也不会出错,因为所有的反射都不是固定类型而是动态加载类型。
· 此时如果要想通过业务层将 Connection 接口对象进行传递,就必须修改DatabaseConnection 的连接类。整个处理操作之中如果要使用 ThreadLocal 类来进行控制处理,那么就建议整体的方法都变为 static 是比较合适的。
首先 Memberservice 的 Connection 不再进行传,直接进行替换后可得到整个代码过程中只传了一个子类对象。
而 DatabaseConnection 要进行一个大的修改,原先是数据库进行连接处理,而现在改为写入 public static Connection rebuild Connection() {,指的是取得一个Connection 的接口对象,而返回的是一个 Connection 对象,即写入@return Connection 对象。
在整个代码的处理过程中,既然都是 static ,那么就要删除private Connection conn;,
将 this.conn =改为 return,否则为 return null 。但代码过程中的 Connection 不能被外部调用,因为 Connection 需要 ThreadLocale 包装,既然要通过ThreadLocale 进行包装,就写 private
static
Thread
L
ocale
thread
L
ocale
=
new
Thread
L
ocale();,
表示保存每一个现成类的对象再进行引用操作,存的则是 Connection,
即表示为
private
static
Thread
L
ocale<Connection>
thread
L
ocale
=
new
Thread
L
ocale<Connection>();。
用户关注的功能有 public static Connection getConnection() {以及public static void close() {,而两种方法都不采取。而此处表示取得一个Connection对象,是通过 ThreadLocal 类对象取得,每一个线程存放自己的对象,返回一个连接对象,即@return 返回一个连接对象。
当用户第一次执行操作时,跟上 Connection conn = threadLocal.get();,
这时表示取得一个 Connection。如果 if(conn == null) {,则表示现在还没有创建 Connection,ThreadLocal 没有保存数据,即写为threadLocal.set(rebuildConnection());,表示为保存对象。但要先进行接收,即conn = rebuildConnection();,表示为建立新的数据库连接对象,
再写为
threadLocal.set(rebuildConnection(conn);。随后 return conn;,此时连接便有了着落。而关闭数据库连接后要注意还是要通过 Connection conn = threadLocal.get();取得保存的对象,如果 if(conn != null){,表示现在还有连接对象,然后写入 conn.close();进行关网,如果 threadLocal 中还有对象则不能进行关网。
写入 threadLocal.remove();,表示清空 ThreadLocal 原本的内容,这时可表示为关闭。在对原始功能进行修改后,一个新的数据库连接类就完成了,原则为使用私有化构造方法去保存,如下:
package cn.mldn.oracle.dbc;
i
mport java.sql.Connection;
i
mport java.sql.DriverManager;
import java.sql.SQLException;
/
**
*
本类负责
O
racle数据库的连接与打开操作处理
*
一旦实例化本类对象,将自动取得相对应的数据库连接
*@
author
mldn
*/
public
class
D
atabase
C
onnection
{
private
static
final
S
tring
DBDRIVER
=
“oracle.
jdbc.driver.OracleDriver”;
private
static
final
S
tring
DBURL
=
“jbdc:oracle:thin:@localhost:1521:M”;
private
static
final
S
tring
DBUSER
=
“scott”;
private
static
final
S
tring
PASSWORD = “tiger”;
private
static
Thread
L
ocale<Connection>
threadLocal = new
Thread
L
ocale<Connection>
() ;
/
**
*
取得一个Connection接口对象
* @
return
C
onnection对象
*
/
p
rivate static
Connection
rebuild
Connection
() ;
try {
Class.forName(DBDRIVER) ;
return
D
river
M
anager.
getConnection() ;
} catch (Except
io
n e) {
e.printStackTrace() ;
}
return null ;
}
/
**
*
取得一个Connection对象,是通过Thread
L
ocal类对象取得
* @
return
返回一个连接对象
*
/
p
ublic static Connection get Connection() {
Connection conn = thread
L
ocal.get() ;
if (conn == null) { //
表示现在还没有创建Connection,
T
hread
L
ocal没有保存数据
conn = rebuildConnection() ; //
建立新的数据库连接对象
threadLocal.set(conn);
}
return conn ;
/**
*
关闭数据库连接
*
/
public
static void close() {
connection conn = threadLocal.get() ;
/
/
取得保存的对象
if (conn !=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
//
现在还有连接对象
}
threadLocal.remove() ;
//
清空
T
hread
L
ocal原本的内容
}
}
}
· 当新的连接类对象完成之后,那么下面如果要想进行数据层的操作使用,直接通过 getConnection()方法就可以重复取出使用的连接对象。
public
M
ember
DAOI
mpl(Connection
conn)
{
this.
conn = DatabaseConnection.getaConnection() ;
· 但是在业务层里面需要进行数据库的连接关闭,而连接关闭直接使用 close()方法即可。
业务层里没有必要再做实例化对象,在业务层调用的时候少了一个实例对象,但如果在多线程的开发之中,每一个线程都有一个业务层的对象时,会发现对象不至少实例化一个而是少了很多,所以对于整个代码来说,一是结构变简单了,而是对象减少了,最重要的是反射变得方便。
· 那么此时的工厂类之中不再需要为 Constructor 类执行调用而痛苦了。
在进行改正后,打开 junit 进行检验操作看是否成功,但出现了 newInstance 错误,而数据层的构造方法应该使用无参,再次进行测试后,测试成功。
三、总结
在以后的项目开发之中,如果是手写代码,那么对于 Connection 数据库的连接控制必须要通过 ThreadLocal 类取得。