一、数据库连接池:

  在一般用JDBC 进行连接数据库进行CRUD操作时,每一次都会:

    通过:java.sql.Connection conn = DriverManager.getConnection(url,user,password); 重新获取一个数据库的链接再进行操作,这样用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。


      
        所以为了减少服务器的压力,便可用连接池的方法:在启动Web应用时,数据就创建好一定数量的Connection链接
  存放到一个容器中,然后当用户请求时,服务器则向容器中获取Connection链接来处理用户的请求,当用户的请求完成后,
  又将该Connection 链接放回到该容器中。这样的一个容器称为连接池。

    
  
  编写一个基本的连接池实现连接复用
       步骤:
       1、建立一个数据库连接池容器。(因为方便存取,则使用LinkedList集合)
       2、初始化一定数量的连接,放入到容器中。
       3、等待用户获取连接对象。(该部分要加锁)
          |---记得删除容器中对应的对象,放置别人同时获取到同一个对象。
       4、提供一个方法,回收用户用完的连接对象。
       5、要遵循先入先出的原则。

  1. import java.io.InputStream;
  2. import java.sql.Connection;
  3. import java.sql.DriverManager;
  4. import java.sql.SQLException;
  5. import java.util.LinkedList;
  6. import java.util.Properties;
  7.  
  8. /**
  9. * 一个基本的数据连接池:
  10. * 1、初始化时就建立一个容器,来存储一定数量的Connection 对象
  11. * 2、用户通过调用MyDataSource 的getConnection 来获取Connection 对象。
  12. * 3、再通过release 方法来回收Connection 对象,而不是直接关闭连接。
  13. * 4、遵守先进先出的原则。
  14. *
  15. *
  16. * @author 贺佐安
  17. *
  18. */
  19. public class MyDataSource {
  20. private static String url = null;
  21. private static String password = null;
  22. private static String user = null ;
  23. private static String DriverClass = null;
  24. private static LinkedList<Connection> pool = new LinkedList<Connection>() ;
  25. // 注册数据库驱动
  26. static {
  27. try {
  28. InputStream in = MyDataSource.class.getClassLoader()
  29. .getResourceAsStream("db.properties");
  30. Properties prop = new Properties();
  31. prop.load(in);
  32. user = prop.getProperty("user");
  33. url = prop.getProperty("url") ;
  34. password = prop.getProperty("password") ;
  35. DriverClass = prop.getProperty("DriverClass") ;
  36. Class.forName(DriverClass) ;
  37.  
  38. } catch (Exception e) {
  39. throw new RuntimeException(e) ;
  40. }
  41. }
  42. //初始化建立数据连接池
  43. public MyDataSource () {
  44. for(int i = 0 ; i < 10 ; i ++) {
  45. try {
  46. Connection conn = DriverManager.getConnection(url, user, password) ;
  47. pool.add(conn) ;
  48. } catch (SQLException e) {
  49. e.printStackTrace();
  50. }
  51. }
  52. }
  53. //、从连接池获取连接
  54. public Connection getConnection() throws SQLException {
  55. return pool.remove() ;
  56. }
  57. // 回收连接对象。
  58. public void release(Connection conn) {
  59. System.out.println(conn+"被回收");
  60. pool.addLast(conn) ;
  61. }
  62. public int getLength() {
  63. return pool.size() ;
  64. }
  65. }

  这样当我们要使用Connection 连接数据库时,则可以直接使用连接池中Connection 的对象。测试如下:

  1. import java.sql.Connection;
  2. import java.sql.SQLException;
  3.  
  4. import org.junit.Test;
  5.  
  6. public class MyDataSourceTest {
  7.  
  8. /**
  9. * 获取数据库连接池中的所有连接。
  10. */
  11. @Test
  12. public void Test() {
  13. MyDataSource mds = new MyDataSource() ;
  14. Connection conn = null ;
  15. try {
  16.  
  17. for (int i = 0 ; i < 20 ; i ++) {
  18. conn = mds.getConnection() ;
  19. System.out.println(conn+"被获取;连接池还有:"+mds.getLength());
  20. mds.release(conn) ;
  21. }
  22. } catch (SQLException e) {
  23. e.printStackTrace();
  24. }
  25. }
  26. }

  再运行的时候,可以发现,循环10次后,又再一次获取到了第一次循环的得到的Connection对象。所以,这样可以大大的减轻数据库的压力。上面只是一个简单的数据库连接池,不完美的便是,回收需要调用数据池的release() 方法来进行回收,那么可以不可以直接调用Connection 实例的close 便完成Connection 对象的回收呢?

二、数据源: 

    > 编写连接池需实现javax.sql.DataSource接口。
      > 实现DataSource接口,并实现连接池功能的步骤:
        1、在DataSource构造函数中批量创建与数据库的连接,并把创建的连接加入LinkedList对象中。

      2、实现getConnection方法,让getConnection方法每次调用时,从LinkedList中取一个Connection返回给用户。当用户使用完Connection,调用Connection.close()方法时,Collection对象应保证将自己返回到LinkedList中,而不要把conn还给数据库。

    利用动态代理和包装设计模式来标准的数据源。

    1、包装设计模式实现标准数据源:

      这里的用包装设计模式,便是将Connection 接口进行包装。简单总结一下包装设计模式的步骤:

          a)定义一个类,实现与被包装类()相同的接口。
                |----可以先自己写一个适配器,然后后面继承这个适配器,改写需要改写的方法,提高编程效率。
             b)定义一个实例变量,记住被包装类的对象的引用。
             c)定义构造方法,转入被包装类的对象。

           e)对需要改写的方法,改写。
                    f)对不需要改写的方法,调用原来被包装类的对应方法。

      所以先编写一个类似适配器的类,将Connection 接口的方法都进行实现:

  1. import java.sql.Array;
  2. import java.sql.Blob;
  3. import java.sql.CallableStatement;
  4. import java.sql.Clob;
  5. import java.sql.Connection;
  6. import java.sql.DatabaseMetaData;
  7. import java.sql.NClob;
  8. import java.sql.PreparedStatement;
  9. import java.sql.SQLClientInfoException;
  10. import java.sql.SQLException;
  11. import java.sql.SQLWarning;
  12. import java.sql.SQLXML;
  13. import java.sql.Savepoint;
  14. import java.sql.Statement;
  15. import java.sql.Struct;
  16. import java.util.Map;
  17. import java.util.Properties;
  18.  
  19. /**
  20. * 实现Connection 的适配器:
  21. * 目的:在使用包装设计模式时方便使用
  22. * @author 贺佐安
  23. *
  24. */
  25.  
  26. public class MyConnectionAdapter implements Connection {
  27. //用一个实例变量,记住被包装类的实例引用
  28. protected Connection conn ;
  29. //构造函数,转入被包装类的对象
  30. public MyConnectionAdapter(Connection conn) {
  31. this.conn = conn ;
  32. }
  33. @Override
  34. public <T> T unwrap(Class<T> iface) throws SQLException {
  35. return conn.unwrap(iface);
  36. }
  37. @Override
  38. public boolean isWrapperFor(Class<?> iface) throws SQLException {
  39. return conn.isWrapperFor(iface);
  40. }
  41. @Override
  42. public Statement createStatement() throws SQLException {
  43. return conn.createStatement();
  44. }
  45. @Override
  46. public PreparedStatement prepareStatement(String sql) throws SQLException {
  47. return conn.prepareStatement(sql);
  48. }
  49. @Override
  50. public CallableStatement prepareCall(String sql) throws SQLException {
  51. return conn.prepareCall(sql);
  52. }
  53. @Override
  54. public String nativeSQL(String sql) throws SQLException {
  55. return conn.nativeSQL(sql);
  56. }
  57. @Override
  58. public void setAutoCommit(boolean autoCommit) throws SQLException {
  59. conn.setAutoCommit(autoCommit);
  60. }
  61. @Override
  62. public boolean getAutoCommit() throws SQLException {
  63. return conn.getAutoCommit();
  64. }
  65. @Override
  66. public void commit() throws SQLException {
  67. conn.commit() ;
  68. }
  69. @Override
  70. public void rollback() throws SQLException {
  71. conn.rollback() ;
  72. }
  73. @Override
  74. public void close() throws SQLException {
  75. conn.close() ;
  76. }
  77. @Override
  78. public boolean isClosed() throws SQLException {
  79. return conn.isClosed();
  80. }
  81. @Override
  82. public DatabaseMetaData getMetaData() throws SQLException {
  83. return conn.getMetaData();
  84. }
  85. @Override
  86. public void setReadOnly(boolean readOnly) throws SQLException {
  87. conn.setReadOnly(readOnly);
  88. }
  89. @Override
  90. public boolean isReadOnly() throws SQLException {
  91. return conn.isReadOnly();
  92. }
  93. @Override
  94. public void setCatalog(String catalog) throws SQLException {
  95. conn.setCatalog(catalog) ;
  96. }
  97. @Override
  98. public String getCatalog() throws SQLException {
  99. return conn.getCatalog();
  100. }
  101. @Override
  102. public void setTransactionIsolation(int level) throws SQLException {
  103. conn.setTransactionIsolation(level) ;
  104. }
  105. @Override
  106. public int getTransactionIsolation() throws SQLException {
  107. return conn.getTransactionIsolation();
  108. }
  109. @Override
  110. public SQLWarning getWarnings() throws SQLException {
  111. return conn.getWarnings();
  112. }
  113. @Override
  114. public void clearWarnings() throws SQLException {
  115. conn.clearWarnings() ;
  116. }
  117. @Override
  118. public Statement createStatement(int resultSetType, int resultSetConcurrency)
  119. throws SQLException {
  120. return conn.createStatement(resultSetType, resultSetConcurrency);
  121.  
  122. }
  123. @Override
  124. public PreparedStatement prepareStatement(String sql, int resultSetType,
  125. int resultSetConcurrency) throws SQLException {
  126. return conn.prepareStatement(sql, resultSetType, resultSetConcurrency);
  127. }
  128. @Override
  129. public CallableStatement prepareCall(String sql, int resultSetType,
  130. int resultSetConcurrency) throws SQLException {
  131. return conn.prepareCall(sql, resultSetType, resultSetConcurrency);
  132. }
  133. @Override
  134. public Map<String, Class<?>> getTypeMap() throws SQLException {
  135. return conn.getTypeMap();
  136. }
  137. @Override
  138. public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
  139. conn.setTypeMap(map) ;
  140. }
  141. @Override
  142. public void setHoldability(int holdability) throws SQLException {
  143. conn.setHoldability(holdability) ;
  144. }
  145. @Override
  146. public int getHoldability() throws SQLException {
  147. return conn.getHoldability();
  148. }
  149. @Override
  150. public Savepoint setSavepoint() throws SQLException {
  151. return conn.setSavepoint();
  152. }
  153. @Override
  154. public Savepoint setSavepoint(String name) throws SQLException {
  155. return conn.setSavepoint(name);
  156. }
  157. @Override
  158. public void rollback(Savepoint savepoint) throws SQLException {
  159. conn.rollback(savepoint);
  160. }
  161. @Override
  162. public void releaseSavepoint(Savepoint savepoint) throws SQLException {
  163. conn.releaseSavepoint(savepoint);
  164. }
  165. @Override
  166. public Statement createStatement(int resultSetType,
  167. int resultSetConcurrency, int resultSetHoldability)
  168. throws SQLException {
  169. return conn.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
  170. }
  171. @Override
  172. public PreparedStatement prepareStatement(String sql, int resultSetType,
  173. int resultSetConcurrency, int resultSetHoldability)
  174. throws SQLException {
  175. return conn.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
  176. }
  177. @Override
  178. public CallableStatement prepareCall(String sql, int resultSetType,
  179. int resultSetConcurrency, int resultSetHoldability)
  180. throws SQLException {
  181. return conn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
  182. }
  183. @Override
  184. public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
  185. throws SQLException {
  186. return conn.prepareStatement(sql, autoGeneratedKeys);
  187. }
  188. @Override
  189. public PreparedStatement prepareStatement(String sql, int[] columnIndexes)
  190. throws SQLException {
  191. return conn.prepareStatement(sql, columnIndexes);
  192. }
  193. @Override
  194. public PreparedStatement prepareStatement(String sql, String[] columnNames)
  195. throws SQLException {
  196. return conn.prepareStatement(sql, columnNames);
  197. }
  198. @Override
  199. public Clob createClob() throws SQLException {
  200. return conn.createClob();
  201. }
  202. @Override
  203. public Blob createBlob() throws SQLException {
  204. return conn.createBlob();
  205. }
  206. @Override
  207. public NClob createNClob() throws SQLException {
  208. return conn.createNClob();
  209. }
  210. @Override
  211. public SQLXML createSQLXML() throws SQLException {
  212. return conn.createSQLXML();
  213. }
  214. @Override
  215. public boolean isValid(int timeout) throws SQLException {
  216. return conn.isValid(timeout);
  217. }
  218. @Override
  219. public void setClientInfo(String name, String value)
  220. throws SQLClientInfoException {
  221. conn.setClientInfo(name, value) ;
  222. }
  223. @Override
  224. public void setClientInfo(Properties properties)
  225. throws SQLClientInfoException {
  226. conn.setClientInfo(properties) ;
  227. }
  228. @Override
  229. public String getClientInfo(String name) throws SQLException {
  230. return conn.getClientInfo(name);
  231. }
  232. @Override
  233. public Properties getClientInfo() throws SQLException {
  234. return conn.getClientInfo();
  235. }
  236. @Override
  237. public Array createArrayOf(String typeName, Object[] elements)
  238. throws SQLException {
  239. return conn.createArrayOf(typeName, elements);
  240. }
  241. @Override
  242. public Struct createStruct(String typeName, Object[] attributes)
  243. throws SQLException {
  244. return conn.createStruct(typeName, attributes);
  245. }
  246.  
  247. }

      然后再对Connection 接口进行包装,将close 方法修改掉:

  1. import java.sql.Connection;
  2. import java.sql.SQLException;
  3. import java.util.LinkedList;
  4. /**
  5. * 对MyConnectionAdapter 进行包装处理
  6. * @author 贺佐安
  7. *
  8. */
  9. public class MyConnectionWrap extends MyConnectionAdapter {
  10.  
  11. private LinkedList<Connection> pool = new LinkedList<Connection>() ;
  12. public MyConnectionWrap(Connection conn ,LinkedList<Connection> pool ) {
  13. super(conn);
  14. this.pool = pool ;
  15. }
  16.  
  17. //改写要实现的方法
  18. public void close() throws SQLException {
  19. pool.addLast(conn) ;
  20. }
  21. }

      编写标准数据源:

  1. import java.io.PrintWriter;
  2. import java.sql.Connection;
  3. import java.sql.DriverManager;
  4. import java.sql.SQLException;
  5. import java.util.LinkedList;
  6. import java.util.ResourceBundle;
  7.  
  8. import javax.sql.DataSource;
  9.  
  10. /**
  11. * 编写标准的数据源:
  12. * 1、实现DataSource 接口
  13. * 2、获取在实现类的构造方法中批量获取Connection 对象,并将这些Connection 存储
  14. * 在LinkedList 容器中。
  15. * 3、实现getConnection() 方法,调用时返回LinkedList容器的Connection对象给用户。
  16. * @author 贺佐安
  17. *
  18. */
  19. public class MyDataSource implements DataSource{
  20. private static String url = null;
  21. private static String password = null;
  22. private static String user = null ;
  23. private static String DriverClass = null;
  24. private static LinkedList<Connection> pool = new LinkedList<Connection>() ;
  25.  
  26. // 注册数据库驱动
  27. static {
  28. try {
  29. ResourceBundle rb = ResourceBundle.getBundle("db") ;
  30. url = rb.getString("url") ;
  31. password = rb.getString("password") ;
  32. user = rb.getString("user") ;
  33. DriverClass = rb.getString("DriverClass") ;
  34. Class.forName(DriverClass) ;
  35.  
  36. //初始化建立数据连接池
  37. for(int i = 0 ; i < 10 ; i ++) {
  38. Connection conn = DriverManager.getConnection(url, user, password) ;
  39. pool.add(conn) ;
  40. }
  41. } catch (Exception e) {
  42. throw new RuntimeException(e) ;
  43. }
  44.  
  45. }
  46. public MyDataSource () {
  47. }
  48.  
  49. //、从连接池获取连接:通过包装模式
  50. public synchronized Connection getConnection() throws SQLException {
  51. if (pool.size() > 0) {
  52. MyConnectionWrap mcw = new MyConnectionWrap(pool.remove(), pool) ;
  53. return mcw ;
  54. }else {
  55. throw new RuntimeException("服务器繁忙!");
  56. }
  57. }
  58.  
  59. // 回收连接对象。
  60. public void release(Connection conn) {
  61. System.out.println(conn+"被回收");
  62. pool.addLast(conn) ;
  63. }
  64.  
  65. public int getLength() {
  66. return pool.size() ;
  67. }
  68.  
  69. @Override
  70. public PrintWriter getLogWriter() throws SQLException {
  71. return null;
  72. }
  73. @Override
  74. public void setLogWriter(PrintWriter out) throws SQLException {
  75.  
  76. }
  77. @Override
  78. public void setLoginTimeout(int seconds) throws SQLException {
  79.  
  80. }
  81. @Override
  82. public int getLoginTimeout() throws SQLException {
  83. return 0;
  84. }
  85. @Override
  86. public <T> T unwrap(Class<T> iface) throws SQLException {
  87. return null;
  88. }
  89. @Override
  90. public boolean isWrapperFor(Class<?> iface) throws SQLException {
  91. return false;
  92. }
  93. @Override
  94. public Connection getConnection(String username, String password)
  95. throws SQLException {
  96. return null;
  97. }
  98.  
  99. }

  2、动态代理实现标准数据源:

    相对于用包装设计来完成标准数据源,用动态代理则方便许多:

  

  1. import java.io.PrintWriter;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. import java.lang.reflect.Proxy;
  5. import java.sql.Connection;
  6. import java.sql.DriverManager;
  7. import java.sql.SQLException;
  8. import java.util.LinkedList;
  9. import java.util.ResourceBundle;
  10.  
  11. import javax.sql.DataSource;
  12.  
  13. /**
  14. * 编写标准的数据源:
  15. * 1、实现DataSource 接口
  16. * 2、获取在实现类的构造方法中批量获取Connection 对象,并将这些Connection 存储
  17. * 在LinkedList 容器中。
  18. * 3、实现getConnection() 方法,调用时返回LinkedList容器的Connection对象给用户。
  19. * @author 贺佐安
  20. *
  21. */
  22. public class MyDataSource implements DataSource{
  23. private static String url = null;
  24. private static String password = null;
  25. private static String user = null ;
  26. private static String DriverClass = null;
  27. private static LinkedList<Connection> pool = new LinkedList<Connection>() ;
  28.  
  29. // 注册数据库驱动
  30. static {
  31. try {
  32. ResourceBundle rb = ResourceBundle.getBundle("db") ;
  33. url = rb.getString("url") ;
  34. password = rb.getString("password") ;
  35. user = rb.getString("user") ;
  36. DriverClass = rb.getString("DriverClass") ;
  37. Class.forName(DriverClass) ;
  38.  
  39. //初始化建立数据连接池
  40. for(int i = 0 ; i < 10 ; i ++) {
  41. Connection conn = DriverManager.getConnection(url, user, password) ;
  42. pool.add(conn) ;
  43. }
  44. } catch (Exception e) {
  45. throw new RuntimeException(e) ;
  46. }
  47. }
  48. public MyDataSource () {
  49.  
  50. }
  51.  
  52. //、从连接池获取连接:通过动态代理
  53. public Connection getConnection() throws SQLException {
  54. if (pool.size() > 0) {
  55. final Connection conn = pool.remove() ;
  56. Connection proxyCon = (Connection) Proxy.newProxyInstance(conn.getClass().getClassLoader(), conn.getClass().getInterfaces(),
  57. new InvocationHandler() {
  58. //策略设计模式:
  59. @Override
  60. public Object invoke(Object proxy, Method method, Object[] args)
  61. throws Throwable {
  62. if("close".equals(method.getName())){
  63. //谁调用,
  64. return pool.add(conn);//当调用close方法时,拦截了,把链接放回池中了
  65. }else{
  66. return method.invoke(conn, args);
  67. }
  68. }
  69. });
  70. return proxyCon ;
  71. }else {
  72. throw new RuntimeException("服务器繁忙!");
  73. }
  74. }
  75.  
  76. public int getLength() {
  77. return pool.size() ;
  78. }
  79.  
  80. @Override
  81. public PrintWriter getLogWriter() throws SQLException {
  82. return null;
  83. }
  84. @Override
  85. public void setLogWriter(PrintWriter out) throws SQLException {
  86.  
  87. }
  88. @Override
  89. public void setLoginTimeout(int seconds) throws SQLException {
  90.  
  91. }
  92. @Override
  93. public int getLoginTimeout() throws SQLException {
  94. return 0;
  95. }
  96. @Override
  97. public <T> T unwrap(Class<T> iface) throws SQLException {
  98. return null;
  99. }
  100. @Override
  101. public boolean isWrapperFor(Class<?> iface) throws SQLException {
  102. return false;
  103. }
  104. @Override
  105. public Connection getConnection(String username, String password)
  106. throws SQLException {
  107. return null;
  108. }
  109. }

    当然觉得麻烦的则可以直接使用一些开源的数据源如:DBCP、C3P0等。DBCP的原理是用包装设计模式开发的数据源,而C3P0则是动态代理的。

    1、DBCP的使用:

  1. import java.io.InputStream;
  2. import java.sql.Connection;
  3. import java.sql.SQLException;
  4. import java.util.Properties;
  5.  
  6. import javax.sql.DataSource;
  7.  
  8. import org.apache.commons.dbcp.BasicDataSourceFactory;
  9.  
  10. /**
  11. * 创建DBCP 工具类
  12. * @author 贺佐安
  13. *
  14. */
  15. public class DbcpUtil {
  16. private static DataSource ds = null ;
  17. static {
  18. try {
  19. //读取配置文件
  20. InputStream in = DbcpUtil.class.getClassLoader().getResourceAsStream("dbcpconfig.properties") ;
  21. Properties prop = new Properties() ;
  22. prop.load(in) ;
  23.  
  24. //通过BasicDataSourceFactory 的creatDataSurce 方法创建 BasicDataSource 对象。
  25. ds = BasicDataSourceFactory.createDataSource(prop) ;
  26.  
  27. } catch (Exception e) {
  28. e.printStackTrace();
  29. }
  30. }
  31. public static DataSource getDs() {
  32. return ds ;
  33. }
  34. public static Connection getConnection () {
  35. try {
  36. return ds.getConnection() ;
  37. } catch (SQLException e) {
  38. throw new RuntimeException() ;
  39. }
  40. }
  41. }

    2、C3P0 的使用:

  1. import java.sql.Connection;
  2. import java.sql.SQLException;
  3.  
  4. import com.mchange.v2.c3p0.ComboPooledDataSource;
  5. /**
  6. * C3P0 开源数据源的使用
  7. * @author 贺佐安
  8. *
  9. */
  10. public class C3p0Util {
  11. private static ComboPooledDataSource cpds = null ;
  12. static {
  13.  
  14. cpds = new ComboPooledDataSource() ;
  15. }
  16. public static Connection getConnection() {
  17. try {
  18. return cpds.getConnection() ;
  19. } catch (SQLException e) {
  20. throw new RuntimeException() ;
  21. }
  22. }
  23. }

  使用这两个数据源时,直接调用获取到的Connection 连接的close 方法,也是将连接放到pool中去。

    

三、元数据(DatabaseMetaData)信息的获取

  > 元数据:数据库、表、列的定义信息。

  > 元数据信息的获取:为了编写JDBC框架使用。

      1、数据库本身信息的获取:java.sql.DataBaseMateData java.sql.Connection.getMetaData() ;

      DataBaseMateData 实现类的常用方法:

        getURL():返回一个String类对象,代表数据库的URL。

        getUserName():返回连接当前数据库管理系统的用户名。

        getDatabaseProductName():返回数据库的产品名称。

        getDatabaseProductVersion():返回数据库的版本号。

        getDriverName():返回驱动驱动程序的名称。

        getDriverVersion():返回驱动程序的版本号。

        isReadOnly():返回一个boolean值,指示数据库是否只允许读操作。

      2、ParameterMetaData: 代表PerparedStatment 中的SQL 参数元数据信息:    java.sql.ParameterMetaData java.sql.PerparedStatement.getParameterMetaData() ;          

      ParameterMetaData 实现类常用方法:

        getParameterCount() :获得指定参数的个数

        getParameterType(int param) :获得指定参数的sql类型(驱动可能不支持)

      3、ResultSetMetaData : 代表结果集的源数据信息:相当于SQL 中的 :DESC    java.sql.ResultSetMetaData java.sql.ResultSet.getMetaData() ;                

      java.sql.ResultSetMetaData 接口中常用的方法:

        a) getColumnCount() : 获取查询方法有几列。

        b) getColumnName(int index) : 获取列名:index从1开始。

        c) getColumnType(int index) : 获取列的数据类型。返回的是TYPES  中的常量值。

四、编写自己的JDBC框架:

    JDBC框架的基本组成:  

    1、核心类:

      a、定义一个指定javax.sql.DataSource 实例的引用变量,通过构造函数获取指定的实例并给定义的变量。
        b、编写SQL运行框架。

         DML 语句的编写:
             1、通过获取的javax.sql.DataSource 实例,获取Connection 对象。
             2、通过ParamenterMeteData 获取数据库元数据。
   
           DQL 语句的编写:
             1、通过获取的DataSource 实例,获取Connection 对象。
             2、通过ParamenterMeteData、ResultSetMetaData 等获取数据库元数据。
             3、用抽象策略设计模式:设计一个ResultSetHandler 接口,作用:将查找出的数据封装到指定的JavaBean中。
                    |————这里的JavaBean,由用户来指定。
                    抽象策略模式,用户可以更具具体的功能来扩展成具体策略设计模式。如:查找的一条信息、查找的所有信息。

  1. import java.sql.Connection;
  2. import java.sql.ParameterMetaData;
  3. import java.sql.PreparedStatement;
  4. import java.sql.ResultSet;
  5. import java.sql.SQLException;
  6. import java.sql.Statement;
  7.  
  8. import javax.sql.DataSource;
  9.  
  10. /**
  11. * 实现JDBC 框架的核心类。
  12. * 在该类中定义了SQL语句完成的方法;
  13. * @author 贺佐安
  14. *
  15. */
  16. public class MyJdbcFrame {
  17. /**
  18. * javax.sql.DataSource 实例的引用变量
  19. */
  20. private DataSource ds = null ;
  21. /**
  22. * 将用户指定的DataSource 指定给系统定义的DataSource 实例的引用变量
  23. * @param ds
  24. */
  25. public MyJdbcFrame(DataSource ds ) {
  26. this.ds = ds ;
  27. }
  28. /**
  29. * 执行UPDATE、DELETE、INSERT 语句。
  30. * @param sql
  31. * @param obj
  32. */
  33. public void update(String sql , Object[] obj) {
  34. Connection conn = null ;
  35. PreparedStatement stmt = null ;
  36. try {
  37. //获取Connection 对象
  38. conn = ds.getConnection() ;
  39. stmt = conn.prepareStatement(sql) ;
  40.  
  41. // 获取ParameterMetaData 元数据对象。
  42. ParameterMetaData pmd = stmt.getParameterMetaData() ;
  43.  
  44. //获取SQL语句中需要设置的参数的个数
  45. int parameterCount = pmd.getParameterCount() ;
  46. if (parameterCount > 0) {
  47. if (obj == null || obj.length != parameterCount) {
  48. throw new MyJdbcFrameException( "parameterCount is error!") ;
  49. }
  50. //设置参数:
  51. for ( int i = 0 ; i < obj.length ; i++) {
  52. stmt.setObject(i+1, obj[i]) ;
  53. }
  54. }
  55. //执行语句:
  56. stmt.executeUpdate() ;
  57.  
  58. } catch(Exception e ) {
  59. throw new MyJdbcFrameException(e.getMessage()) ;
  60. } finally {
  61. release(stmt, null, conn) ;
  62. }
  63. }
  64.  
  65. public Object query(String sql , Object[] obj , ResultSetHandler rsh) {
  66. Connection conn = null ;
  67. PreparedStatement stmt = null ;
  68. ResultSet rs = null ;
  69. try {
  70. //获取Connection 对象
  71. conn = ds.getConnection() ;
  72. stmt = conn.prepareStatement(sql) ;
  73.  
  74. // 获取ParameterMetaData 元数据对象。
  75. ParameterMetaData pmd = stmt.getParameterMetaData() ;
  76.  
  77. //获取SQL语句中需要设置的参数的个数
  78. int parameterCount = pmd.getParameterCount() ;
  79.  
  80. if (obj.length != parameterCount) {
  81. throw new MyJdbcFrameException( "'" +sql +"' : parameterCount is error!") ;
  82. }
  83. //设置参数:
  84. for ( int i = 0 ; i < obj.length ; i++) {
  85. stmt.setObject(i+1, obj[i]) ;
  86. }
  87. //执行语句:
  88. rs = stmt.executeQuery();
  89.  
  90. return rsh.handler(rs);
  91. } catch(Exception e ) {
  92. throw new MyJdbcFrameException(e.getMessage()) ;
  93. } finally {
  94. release(stmt, null, conn) ;
  95. }
  96. }
  97. /**
  98. * 释放资源
  99. * @param stmt
  100. * @param rs
  101. * @param conn
  102. */
  103. public static void release(Statement stmt
  104. , ResultSet rs
  105. , Connection conn) {
  106. if(rs != null) {
  107. try {
  108. rs.close() ;
  109. } catch (SQLException e) {
  110. e.printStackTrace();
  111. }
  112. rs = null ;
  113. }
  114. if (stmt != null) {
  115. try {
  116. stmt.close();
  117. } catch (SQLException e) {
  118. e.printStackTrace();
  119. }
  120. stmt = null ;
  121. }
  122. if (conn != null) {
  123. try {
  124. conn.close();
  125. } catch (SQLException e) {
  126. e.printStackTrace();
  127. }
  128. conn = null ;
  129. }
  130. }
  131.  
  132. }

    2、接口:策略模式的接口:ResultSetHandler 。

  1. import java.sql.ResultSet;
  2.  
  3. //抽象策略模式
  4. public interface ResultSetHandler {
  5. public Object handler(ResultSet rs) ;
  6. }

    这里对ResultSetHandler 接口实现一个BeanHandler 实例 :

  1. import java.lang.reflect.Field;
  2. import java.sql.ResultSet;
  3. import java.sql.ResultSetMetaData;
  4.  
  5. /**
  6. * 该类获取ResultSet 结果集中的第一个值,封装到JavaBean中
  7. * @author 贺佐安
  8. *
  9. */
  10. public class BeanHandler implements ResultSetHandler {
  11. //获取要封装的JavaBean的字节码
  12. private Class clazz ;
  13. public BeanHandler (Class clazz) {
  14. this.clazz = clazz ;
  15. }
  16.  
  17. public Object handler(ResultSet rs) {
  18. try {
  19. if (rs.next()) {
  20. //1、获取结果集的元数据。
  21. ResultSetMetaData rsm = rs.getMetaData() ;
  22. //2、创建JavaBean的实例:
  23. Object obj = clazz.newInstance() ;
  24. //3、将数据封装到JavaBean中。
  25. for (int i = 0 ; i < rsm.getColumnCount() ; i ++) {
  26. //获取属性名
  27. String columnName = rsm.getColumnName(i+1) ;
  28. //获取属性值
  29. Object value = rs.getObject(i+1) ;
  30.  
  31. Field objField = obj.getClass().getDeclaredField(columnName) ;
  32. objField.setAccessible(true) ;
  33. objField.set(obj, value) ;
  34. }
  35. return obj ;
  36. } else {
  37. return null ;
  38. }
  39. } catch (Exception e) {
  40. throw new RuntimeException(e) ;
  41. }
  42. }
  43. }

    3、自定义异常类:继承RuntimeException。如:

  1. public class MyJdbcFrameException extends RuntimeException {
  2. public MyJdbcFrameException() {
  3. super() ;
  4. }
  5. public MyJdbcFrameException(String e) {
  6. super(e) ;
  7. }
  8. }

    

  然后就可以将其打包发布,在以后写数据库操作时就可以用自己的JDBC框架了,如果要完成查询多条语句什么的,则要实现ResultSetHandler 接口。来完成更多的功能。

  当然,使用DBUtils 则更简单:Apache 组织提供的一个开源JDBC 工具类库。

    

 

--------------------------------------------------------------------------------------学习时的总结。2013年7月18日 19:29:44

【总结】编写自己的JDBC框架的更多相关文章

  1. javaweb学习总结(四十)——编写自己的JDBC框架

    一.元数据介绍 元数据指的是"数据库"."表"."列"的定义信息. 1.1.DataBaseMetaData元数据 Connection.g ...

  2. 编写自定义的JDBC框架与策略模式

    本篇根据上一篇利用数据库的几种元数据来仿造Apache公司的开源DbUtils工具类集合来编写自己的JDBC框架.也就是说在本篇中很大程度上的代码都和DbUtils中相似,学完本篇后即更容易了解DbU ...

  3. javaweb总结(四十)——编写自己的JDBC框架

    一.元数据介绍 元数据指的是"数据库"."表"."列"的定义信息. 1.1.DataBaseMetaData元数据 Connection.g ...

  4. 编写自己的JDBC框架(转)

    一.元数据介绍 元数据指的是"数据库"."表"."列"的定义信息. 1.1.DataBaseMetaData元数据 Connection.g ...

  5. java web学习总结(二十三) -------------------编写自己的JDBC框架

    一.元数据介绍 元数据指的是"数据库"."表"."列"的定义信息. 1.1.DataBaseMetaData元数据 Connection.g ...

  6. JDBC 学习复习10 编写自己的JDBC框架

    首先万分感谢狼哥 孤傲苍狼 博客,整个jdbc学习的博客资料 链接为http://www.cnblogs.com/xdp-gacl/p/4006830.html 详细代码见狼哥博客,列出我学习过程中遇 ...

  7. 编写自己的JDBC框架

    目的 简化代码,提高开发效率 设计模式 策略设计模式 代码 #连接设置 driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost ...

  8. JDBC框架

    一.元数据介绍 元数据指的是"数据库"."表"."列"的定义信息. 1.1.DataBaseMetaData元数据 Connection.g ...

  9. Spring的JDBC框架

    转自: http://www.cnblogs.com/windlaughing/p/3287750.html Spring JDBC提供了一套JDBC抽象框架,用于简化JDBC开发. Spring主要 ...

随机推荐

  1. 在ios中使用第三方类库

    在项目开发中经常会用到一些第三方类库,通常有两种方法来做到:一种方法是直接把所有的.h和.m文件复制到项目中:另一种方法是把.xcodeproj拖到项目中生成静态链接库并引用. 方法一:直接复制所有源 ...

  2. 我的Linux随笔目录

    现在整理博客的时间少了,大多是在用为知笔记收藏和整理,一次集中发点Linux相关随笔整理和一个目录,是按时间顺序来的.每一篇都是自己用过之后整理的,应用场景已经尽可能的说明了,不明白的可以Q我,上班时 ...

  3. Dynamic CRM 2013学习笔记(十二)实现子表合计(汇总,求和)功能的通用插件

    上一篇 Dynamic CRM 2013学习笔记(十一)利用Javascript实现子表合计(汇总,求和)功能 , 介绍了如何用js来实现子表合计功能,这种方法要求在各个表单上添加js方法,如果有很多 ...

  4. Vertica笔记

    1.Table不做存储,本质是一个视图,真正存储在 Projection 里.可以针对一个Table建多个Projection . 查看表和 Projection 的个数: select anchor ...

  5. [ucgui] 对话框6——触屏位置简单例子

    >_<:直接调用函数获得触屏位置: xPhys = GUI_TOUCH_GetxPhys(); /* Get the A/D mesurement result in x */ yPhys ...

  6. SharePoint API如何处理时区问题

    使用SharePoint API,我们经常会有时区转换的问题,SharePoint API 本身如何处理时区问题的呢? 本文主要以Modified字段为例测试相关API的行为. CSOM API测试: ...

  7. SpringMVC从一个controller跳转到另一个controller

    return "redirect:……路径……"; @RequestMapping(value = "/index", method = RequestMeth ...

  8. crossplatform---Node.js Applications with VS Code

    Node.js is a platform for building fast and scalable server applications using JavaScript. Node.js i ...

  9. paip.语义相关是否可在 哈米 的语义分析中应用

    paip.语义相关是否可在 哈米 的语义分析中应用 作者Attilax  艾龙,  EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csdn. ...

  10. paip.判断文件是否存在uapi python php java c#

    paip.判断文件是否存在uapi python php java c# ==========uapi file_exists exists() 面向对象风格:  File.Exists 作者: 老哇 ...