JAva jdbcの理解(connectionとthreadlocalとデータベース接続プールとトランザクション)
21622 ワード
1.jdbcはデータベースに接続し、このようにします.
Class.forName("com.mysql.jdbc.Driver"); java.sql.Connection conn = DriverManager.getConnection(jdbcUrl);
2.jdbc url用Drivermanagerに転送する.getConnection(jdbcurl)接続データベース、
注意:Drivermanager.getConnection(jdbcurl)取得は1つのconnectionにすぎず,高同時性を満たすことはできない.connectionはスレッドが安全ではないので、1つのconnectionは1つのものに対応しています.
3.したがって、データベース接続プールは、複数回のDrivermanagerである.getConnection(jdbcurl)は、複数のconnectionを取得してhashmapに入れます.
4.connectionを取得するたびにcpuリソースとメモリリソースを浪費する必要があり、リソースを浪費します.データベース接続プールが誕生しました
5.データベース接続プール部分のソースコード:
気をつけてgetConnection()は、threadlocalから先に取り、threadlocalにある場合は、スレッド内の複数のdao操作を保証し、同じconnectionを使用してトランザクションを保証します.
新しいスレッドの場合は、新しいconnectionをthreadlocalに入れ、スレッドにgetします.
次のいくつかの方法に重点を置いて、データベース接続プールがthreadlocalにconnectionを入れて、各スレッドが接続プールから得たのがスレッド独自のconnectionであることを保証することを説明します.
//スレッドと接続をバインドし、トランザクションが を統一的に実行できることを保証します.メンバー変数private static ThreadLocal threadLocal=new ThreadLocal()
//スレッドと接続をバインドし、トランザクションが を統一的に実行できることを保証します. private static ThreadLocal threadLocal = new ThreadLocal();
Why ThreadLocal?
いずれにしても、マルチスレッドセキュリティ(Thread-safe)のプログラムを作成することは困難であり、スレッドがリソースを共有するためには、共有リソースを慎重に同期させなければならず、同期に一定の効率的な遅延をもたらす一方、同期を処理する際には、オブジェクトのロックと解放に注意し、デッドロックを生じないようにしなければならない.様々な要因により,マルチスレッドプログラムの作成が困難になる.
マルチスレッド共有リソースの問題を別の角度から考えてみましょう.共有リソースがこんなに難しい以上、共有しないでください.スレッドごとにリソースのコピーを作成しませんか.各スレッドがデータにアクセスする行為を分離し、実現する方法は、各スレッドにそのスレッドが享受するリソースを保管するための特定の空間を与えることである.
ThreadLocalとは?
名前の通り、local variable(スレッドローカル変数)です.その機能は非常に簡単です.この変数を使用するスレッドごとに変数値のコピーを提供し、各スレッドが他のスレッドとの副本衝突を起こさずに独立して自分のコピーを変更できるようにします.スレッドの観点から見ると、各スレッドが変数を完全に持っているように見えます.
シーンの操作 To keep state with a thread (user-id, transaction-id, logging-id) To cache objects which you need frequently
ThreadLocalクラスはスレッド範囲の共有変数を実現する
これは主に4つの方法からなるinitialValue(),get(),set(T),remove()であり,ここで注目すべきはinitialValue()であり,この方法はprotectedの方法であり,明らかにサブクラスの書き換えのためにわざわざ実現されている.このメソッドは、現在のスレッドがスレッドローカル変数の初期値を返します.このメソッドは、1つのスレッドがget()またはset(Object)を1回目に呼び出したときに実行され、1回のみ実行される遅延呼び出しメソッドです.ThreadLocalの実装はnullを直接返します.
ThreadLocalの原理
ThreadLocalはどのようにして各スレッドの変数のコピーを維持しますか?実装の構想は簡単で,ThreadLocalクラスには各スレッドの変数のコピーを格納するためのMapがある.たとえば、次のような実装例があります.
public class ThreadLocal{ private Map values = Collections.synchronizedMap(new HashMap()); public Object get() { Thread curThread = Thread.currentThread(); Object o = values.get(curThread); if (o == null && !values.containsKey(curThread)) { o = initialValue(); values.put(curThread, o); } return o; }
public void set(Object newValue) { values.put(Thread.currentThread(), newValue); }
public Object initialValue() { return null; }}
ThreadLocalの使用
使用方法1:
hibernateのドキュメントには、ThreadLocalにマルチスレッドアクセスを管理する部分が表示されます.具体的なコードは以下の通りである. public static final ThreadLocal session = new ThreadLocal();2. public static Session currentSession() {3. Session s = (Session)session.get();4. //open a new session,if this session has none5. if(s == null){6. s = sessionFactory.openSession();7. session.set(s);8. } return s;9.}逐行分析1.ThreadLocalオブジェクトを初期化します.ThreadLocalには、get()、set()、initialvalue()の3つのメンバーメソッドがあります.initialvalueを初期化しない場合、initialvalueはnullを返します.3. セッションのgetは、現在のスレッドに基づいて対応するスレッド内部変数、すなわちnetを返す.sf.hibernate.Session(対応する各データベース接続に相当する).マルチスレッドの場合はデータベースリンクを共有するのは安全ではない.ThreadLocalは各スレッドに独自のs(データベース接続)があることを保証する.5.このスレッドが初めてアクセスする場合、自然にs(データベース接続)はnullになり、次に行6.6であるSessionを作成します.データベース接続インスタンスs 7を作成します.このデータベース接続sをThreadLocalに保存します.8.現在のスレッドがデータベースにアクセスしている場合は、sessionからget()を選択すると、スレッドが最後に取得した接続インスタンスを取得できます.
使用方法2
スレッドに特別な値を初期化するには、ThreadLocalのサブクラスを独自に実装して書き換える必要があります.通常、内部匿名クラスを使用してThreadLocalをサブクラス化します.EasyDBOでjdbc接続コンテキストを作成するには、次のようにします.
public class JDBCContext{ private static Logger logger = Logger.getLogger(JDBCContext.class); private DataSource ds; protected Connection connection; private boolean isValid = true; private static ThreadLocal jdbcContext; private JDBCContext(DataSource ds){ this.ds = ds; createConnection(); } public static JDBCContext getJdbcContext(javax.sql.DataSource ds) { if(jdbcContext==null)jdbcContext=new JDBCContextThreadLocal(ds); JDBCContext context = (JDBCContext) jdbcContext.get(); if (context == null) { context = new JDBCContext(ds); } return context; }
private static class JDBCContextThreadLocal extends ThreadLocal { public javax.sql.DataSource ds; public JDBCContextThreadLocal(javax.sql.DataSource ds) { this.ds=ds; } protected synchronized Object initialValue() { return new JDBCContext(ds); } }}
単一例モードでは、getJdbcContext()を呼び出して独自のjdbcContextを取得し、JDBCContextThreadLocalにサブクラスを内蔵してJDBCContextオブジェクトのスレッドローカル変数を取得します.
この文書の一部はhttp://blog.csdn.net/wenzhihui_2010/article/details/8985575
Class.forName("com.mysql.jdbc.Driver"); java.sql.Connection conn = DriverManager.getConnection(jdbcUrl);
2.jdbc url用Drivermanagerに転送する.getConnection(jdbcurl)接続データベース、
注意:Drivermanager.getConnection(jdbcurl)取得は1つのconnectionにすぎず,高同時性を満たすことはできない.connectionはスレッドが安全ではないので、1つのconnectionは1つのものに対応しています.
3.したがって、データベース接続プールは、複数回のDrivermanagerである.getConnection(jdbcurl)は、複数のconnectionを取得してhashmapに入れます.
4.connectionを取得するたびにcpuリソースとメモリリソースを浪費する必要があり、リソースを浪費します.データベース接続プールが誕生しました
5.データベース接続プール部分のソースコード:
気をつけてgetConnection()は、threadlocalから先に取り、threadlocalにある場合は、スレッド内の複数のdao操作を保証し、同じconnectionを使用してトランザクションを保証します.
新しいスレッドの場合は、新しいconnectionをthreadlocalに入れ、スレッドにgetします.
次のいくつかの方法に重点を置いて、データベース接続プールがthreadlocalにconnectionを入れて、各スレッドが接続プールから得たのがスレッド独自のconnectionであることを保証することを説明します.
//
public Connection getCurrentConnecton(){
//
Connection conn = threadLocal.get();
if(!isValid(conn)){
conn = getConnection();
}
return conn; }
//
public synchronized Connection getConnection() {
Connection conn = null;
try {
//
if(contActive < this.dbBean.getMaxActiveConnections()){
if (freeConnection.size() > 0) {
conn = freeConnection.get(0); if (conn != null) { threadLocal.set(conn); } freeConnection.remove(0); } else { conn = newConnection(); } }else{ // , wait(this.dbBean.getConnTimeOut()); conn = getConnection(); } if (isValid(conn)) { activeConnection.add(conn); contActive ++; } } catch (SQLException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } return conn; }
public synchronized void releaseConn(Connection conn) throws SQLException {
if (isValid(conn)&& !(freeConnection.size() > dbBean.getMaxConnections())) {
freeConnection.add(conn);
activeConnection.remove(conn);
contActive --;
threadLocal.remove();
// ,
notifyAll();
}
}
,LZ . , ThreadLocal???
, , connection , , , ,cop3,proxy ;
ThreadLocal ? , , ,
servlet . ,servlet ?
class MyServlet extends HttpServlet{
private Connection conn;
}
ok, , conn , servlet , Connection, . , , .
Connection . ThreadLocal , .
private ThreadLocal ct = new ThreadLocal();
Connection,set ct , get , Connection , .
Hibernate connection threadlocal !!!
Hibernate connection threadlocal !!!
Hibernate connection threadlocal !!!
public class ConnectionPool implements IConnectionPool {
//
private DBbean dbBean;
private boolean isActive = false; //
private int contActive = 0;//
//
private List freeConnection = new Vector();
//
private List activeConnection = new Vector();
public ConnectionPool(DBbean dbBean) {
super();
this.dbBean = dbBean;
init();
cheackPool();
}
//
public void init() {
try {
Class.forName(dbBean.getDriverName());
for (int i = 0; i < dbBean.getInitConnections(); i++) {
Connection conn;
conn = newConnection();
//
if (conn != null) {
freeConnection.add(conn);
contActive++;
}
}
isActive = true;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
//
public Connection getCurrentConnecton(){
//
Connection conn = threadLocal.get();
if(!isValid(conn)){
conn = getConnection();
}
return conn;
}
//
public synchronized Connection getConnection() {
Connection conn = null;
try {
//
if(contActive < this.dbBean.getMaxActiveConnections()){
if (freeConnection.size() > 0) {
conn = freeConnection.get(0);
if (conn != null) {
threadLocal.set(conn);
}
freeConnection.remove(0);
} else {
conn = newConnection();
}
}else{
// ,
wait(this.dbBean.getConnTimeOut());
conn = getConnection();
}
if (isValid(conn)) {
activeConnection.add(conn);
contActive ++;
}
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return conn;
}
//
private synchronized Connection newConnection()
throws ClassNotFoundException, SQLException {
Connection conn = null;
if (dbBean != null) {
Class.forName(dbBean.getDriverName());
conn = DriverManager.getConnection(dbBean.getUrl(),
dbBean.getUserName(), dbBean.getPassword());
}
return conn;
}
//
public synchronized void releaseConn(Connection conn) throws SQLException {
if (isValid(conn)&& !(freeConnection.size() > dbBean.getMaxConnections())) {
freeConnection.add(conn);
activeConnection.remove(conn);
contActive --;
threadLocal.remove();
// ,
notifyAll();
}
}
//
private boolean isValid(Connection conn) {
try {
if (conn == null || conn.isClosed()) {
return false;
}
} catch (SQLException e) {
e.printStackTrace();
}
return true;
}
//
public synchronized void destroy() {
for (Connection conn : freeConnection) {
try {
if (isValid(conn)) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
for (Connection conn : activeConnection) {
try {
if (isValid(conn)) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
isActive = false;
contActive = 0;
}
//
@Override
public boolean isActive() {
return isActive;
}
//
@Override
public void cheackPool() {
if(dbBean.isCheakPool()){
new Timer().schedule(new TimerTask() {
@Override
public void run() {
// 1.
// 2.
// 3. , ,
System.out.println(" :"+freeConnection.size());
System.out.println(" ::"+activeConnection.size());
System.out.println(" :"+contActive);
}
},dbBean.getLazyCheck(),dbBean.getPeriodCheck());
}
}
}
Why ThreadLocal?
いずれにしても、マルチスレッドセキュリティ(Thread-safe)のプログラムを作成することは困難であり、スレッドがリソースを共有するためには、共有リソースを慎重に同期させなければならず、同期に一定の効率的な遅延をもたらす一方、同期を処理する際には、オブジェクトのロックと解放に注意し、デッドロックを生じないようにしなければならない.様々な要因により,マルチスレッドプログラムの作成が困難になる.
マルチスレッド共有リソースの問題を別の角度から考えてみましょう.共有リソースがこんなに難しい以上、共有しないでください.スレッドごとにリソースのコピーを作成しませんか.各スレッドがデータにアクセスする行為を分離し、実現する方法は、各スレッドにそのスレッドが享受するリソースを保管するための特定の空間を与えることである.
ThreadLocalとは?
名前の通り、local variable(スレッドローカル変数)です.その機能は非常に簡単です.この変数を使用するスレッドごとに変数値のコピーを提供し、各スレッドが他のスレッドとの副本衝突を起こさずに独立して自分のコピーを変更できるようにします.スレッドの観点から見ると、各スレッドが変数を完全に持っているように見えます.
シーンの操作
ThreadLocalクラスはスレッド範囲の共有変数を実現する
これは主に4つの方法からなるinitialValue(),get(),set(T),remove()であり,ここで注目すべきはinitialValue()であり,この方法はprotectedの方法であり,明らかにサブクラスの書き換えのためにわざわざ実現されている.このメソッドは、現在のスレッドがスレッドローカル変数の初期値を返します.このメソッドは、1つのスレッドがget()またはset(Object)を1回目に呼び出したときに実行され、1回のみ実行される遅延呼び出しメソッドです.ThreadLocalの実装はnullを直接返します.
ThreadLocalの原理
ThreadLocalはどのようにして各スレッドの変数のコピーを維持しますか?実装の構想は簡単で,ThreadLocalクラスには各スレッドの変数のコピーを格納するためのMapがある.たとえば、次のような実装例があります.
public class ThreadLocal{ private Map values = Collections.synchronizedMap(new HashMap()); public Object get() { Thread curThread = Thread.currentThread(); Object o = values.get(curThread); if (o == null && !values.containsKey(curThread)) { o = initialValue(); values.put(curThread, o); } return o; }
public void set(Object newValue) { values.put(Thread.currentThread(), newValue); }
public Object initialValue() { return null; }}
ThreadLocalの使用
使用方法1:
hibernateのドキュメントには、ThreadLocalにマルチスレッドアクセスを管理する部分が表示されます.具体的なコードは以下の通りである. public static final ThreadLocal session = new ThreadLocal();2. public static Session currentSession() {3. Session s = (Session)session.get();4. //open a new session,if this session has none5. if(s == null){6. s = sessionFactory.openSession();7. session.set(s);8. } return s;9.}逐行分析1.ThreadLocalオブジェクトを初期化します.ThreadLocalには、get()、set()、initialvalue()の3つのメンバーメソッドがあります.initialvalueを初期化しない場合、initialvalueはnullを返します.3. セッションのgetは、現在のスレッドに基づいて対応するスレッド内部変数、すなわちnetを返す.sf.hibernate.Session(対応する各データベース接続に相当する).マルチスレッドの場合はデータベースリンクを共有するのは安全ではない.ThreadLocalは各スレッドに独自のs(データベース接続)があることを保証する.5.このスレッドが初めてアクセスする場合、自然にs(データベース接続)はnullになり、次に行6.6であるSessionを作成します.データベース接続インスタンスs 7を作成します.このデータベース接続sをThreadLocalに保存します.8.現在のスレッドがデータベースにアクセスしている場合は、sessionからget()を選択すると、スレッドが最後に取得した接続インスタンスを取得できます.
使用方法2
スレッドに特別な値を初期化するには、ThreadLocalのサブクラスを独自に実装して書き換える必要があります.通常、内部匿名クラスを使用してThreadLocalをサブクラス化します.EasyDBOでjdbc接続コンテキストを作成するには、次のようにします.
public class JDBCContext{ private static Logger logger = Logger.getLogger(JDBCContext.class); private DataSource ds; protected Connection connection; private boolean isValid = true; private static ThreadLocal jdbcContext; private JDBCContext(DataSource ds){ this.ds = ds; createConnection(); } public static JDBCContext getJdbcContext(javax.sql.DataSource ds) { if(jdbcContext==null)jdbcContext=new JDBCContextThreadLocal(ds); JDBCContext context = (JDBCContext) jdbcContext.get(); if (context == null) { context = new JDBCContext(ds); } return context; }
private static class JDBCContextThreadLocal extends ThreadLocal { public javax.sql.DataSource ds; public JDBCContextThreadLocal(javax.sql.DataSource ds) { this.ds=ds; } protected synchronized Object initialValue() { return new JDBCContext(ds); } }}
単一例モードでは、getJdbcContext()を呼び出して独自のjdbcContextを取得し、JDBCContextThreadLocalにサブクラスを内蔵してJDBCContextオブジェクトのスレッドローカル変数を取得します.
この文書の一部はhttp://blog.csdn.net/wenzhihui_2010/article/details/8985575