JDBC(java Database Connectivity)java數據庫鏈接,是一種用於執行上sql語句的javaAPI,能夠爲多種關係型數據庫提供統一訪問接口。咱們項目中常常用到的MySQL、oracle、DB2等關係型數據庫均是經過JDBC來訪問的,如今主流的ORM框架Hibernate、Mybatis等均是在JDBC的基礎上作的進一步封裝、優化。通常小型的項目,能夠直接用JDBC來訪問數據庫,簡單方便。我在進過幾個項目後,總結了三總JDBC的基本用法,對這幾種用法作一個總結。java
鏈接池經過將已經創建好的鏈接保存在鏈接池中,當有請求的時候,直接使接對數據庫進行訪問,從而節省了建立鏈接和關閉鏈接的時間,性能獲得了提升,總之一句話,鏈接池就是爲了提高性能。經常使用的鏈接池有DBCP、c3p0、DRUID等,原理都同樣。下面是實例:mysql
首先建立鏈接池:sql
public class ConnDBUtil{ private static final Log logger = LogFactory.getLog(ConnDBUtil.class); private static Properties JDBCPOP = new PropertiesUtil().getProperties("jdbc.properties"); private static ComboPooledDataSource cpds; static{ try { cpds = new ComboPooledDataSource(); cpds.setDriverClass(JDBCPOP.getProperty("driverName")); cpds.setJdbcUrl(JDBCPOP.getProperty("url")); cpds.setUser(JDBCPOP.getProperty("user")); cpds.setPassword(JDBCPOP.getProperty("drowssap")); cpds.setAcquireIncrement(Integer.parseInt(JDBCPOP.getProperty("acquireIncrement"))); cpds.setInitialPoolSize(Integer.parseInt(JDBCPOP.getProperty("initialPoolSize"))); cpds.setMinPoolSize(Integer.parseInt(JDBCPOP.getProperty("minPoolSize"))); cpds.setMaxPoolSize(Integer.parseInt(JDBCPOP.getProperty("maxPoolSize"))); cpds.setIdleConnectionTestPeriod(Integer.parseInt(JDBCPOP .getProperty("idleConnectionTestPeriod"))); } catch (PropertyVetoException e) { logger.error("c3p0鏈接異常:"+e.getMessage(),e); } } /** * 得到c3p0鏈接 * @return Connection */ public Connection getConnection(){ Connection conn = null; try { conn= cpds.getConnection(); } catch (SQLException e) { logger.error(e.getMessage(),e); e.fillInStackTrace(); } return conn; } public void c3p0Static(ComboPooledDataSource cpds){ try { logger.info("c3p0總鏈接數:"+cpds.getNumConnections()); logger.info("c3p0正在使用鏈接數:"+cpds.getNumBusyConnections()); logger.info("c3p0空閒鏈接數:"+cpds.getNumIdleConnections()); } catch (SQLException e) { logger.error(e.getMessage(),e); } }
接下來獲取鏈接,jdbc操做數據庫,以一個簡單的查詢爲例:數據庫
public class Dao{ public String queryHtable(String username) { Connection conn=null; PreparedStatement ps=null; ResultSet rs=null; String HTable=null; try { String sql="select tab_name FROM table_user " + "WHERE USER_NAME='"+username+"'"; conn=ConnDBUtil.getConnection(); ps=conn.prepareStatement(sql); rs=ps.executeQuery(); while(rs.next()){ HTable=rs.getString("USE_HTABLE"); } } catch (SQLException e) { logger.error(e.getMessage(),e); e.fillInStackTrace(); }finally{ closeAll(rs, ps, conn); } return HTable; } //關閉資源 private static void closeAll(ResultSet rs, PreparedStatement ps, Connection conn) { if(rs != null){ try { rs.close(); } catch (SQLException e) { logger.error(e.getMessage(),e); e.fillInStackTrace(); } } if(ps != null){ try { ps.close(); } catch (SQLException e) { logger.error(e.getMessage(),e); e.fillInStackTrace(); } } if(conn != null){ try { conn.close(); } catch (SQLException e) { logger.error(e.getMessage(),e); e.fillInStackTrace(); } } }
以上就是一種很是簡單的JDBC操做數據庫的例子,缺點是代碼耦合度很是高。安全
ThreadLocal,線程局部變量,做用很是簡單就是爲每個使用該變量的線程提供一個變量值的副本,這樣,每個線程均可以獨立改變本身的副本而不受其餘線程的影響,也不會和其餘線程副本衝突,從而提升線程安全性,也就是說,每個線程徹底擁有該變量。從源碼咱們能夠看到ThreadLocal是如何維護線程變量副本的,思路很簡單,ThreadLocal類中存在一個Map,Map中存儲的就是變量副本。oracle
public class GetConnectionType { public static Connection getConnection() throws SQLException, ClassNotFoundException { String url = "jdbc:mysql://localhost:3306/test"; String driver = "com.mysql.jdbc.Driver"; String username = "root"; String password = "123456"; Class.forName(driver); Connection connection = DriverManager.getConnection(url, username, password); return connection; } }
public class GetConnection { private static ThreadLocal<Connection> local = new ThreadLocal<>(); //獲取鏈接 public static Connection getConnection() throws ClassNotFoundException, SQLException { Connection conn = local.get(); if (conn == null) { conn = GetConnectionType.getConnection(); conn.setAutoCommit(false); local.set(conn); } return conn; } //提交事務 public static void commit() { try { if (local.get() != null) { local.get().commit(); local.get().close(); local.set(null); } } catch (SQLException e) { e.printStackTrace(); } } //回滾 public static void rollback() { try { if (local.get() != null) { local.get().rollback(); local.get().close(); local.set(null); } } catch (SQLException e) { e.printStackTrace(); } } }
public List<Bookinfo> getAllBookinfo() throws SQLException, ClassNotFoundException { List listBookinfo = new ArrayList(); String sql = "select * from bookinfo order by id asc"; Connection conn = GetConnection.getConnection(); PreparedStatement ps = conn.prepareStatement(sql); ResultSet rs = ps.executeQuery(); while (rs.next()) { int idDB = rs.getInt("id"); String booknameDB = rs.getString("bookname"); double bookpriceDB = rs.getDouble("bookprice"); Bookinfo bookinfo = new Bookinfo(); bookinfo.setId(idDB); bookinfo.setBookname(booknameDB); bookinfo.setBookprice(bookpriceDB); listBookinfo.add(bookinfo); } rs.close(); ps.close(); return listBookinfo; }
什麼是反射?反射就是對於任何一個類,,都可以知道這個類的全部屬性和方法;對於任意一個對象,都可以任意調用它的任何方法和屬性;這種動態獲取信息以及動態調用對象方法的功能稱爲java語言的反射機制。(來自:百度百科)。代碼以下:框架
public class ConnUtil { private static Log logger = LogFactory.getLog(ConnUtil.class); private static String sqlDriver; private static String url; private static String username; private static String password; private static Properties JDBCP = new PropertiesUtil().getProperties("jdbc.properties"); static{ try { sqlDriver=JDBCP.getProperty("driverName"); url=JDBCP.getProperty("url"); username=JDBCP.getProperty("user"); password=JDBCP.getProperty("drowssap"); Class.forName(sqlDriver); } catch (ClassNotFoundException e) { logger.error("mysql註冊驅動出錯:"+e.getMessage(),e); } } /** * 獲取數據庫鏈接 * @return Connection */ public static Connection getConn(){ Connection connection=null; try { connection= DriverManager.getConnection(url, username, password); } catch (SQLException e) { logger.error("數據庫創建鏈接出錯:"+e.getMessage(),e); } return connection; } /** * 關閉鏈接 * @param objects */ public static void close(Object...objects){ try { if(objects!=null){ for(Object obj:objects){ if(obj instanceof Connection){ ((Connection) obj).close(); }else if(obj instanceof PreparedStatement){ ((PreparedStatement) obj).close(); }else if(obj instanceof ResultSet){ ((ResultSet) obj).close(); } } } } catch (SQLException e) { logger.error("數據庫鏈接關閉異常:"+e.getMessage(),e); } } }
數據庫鏈接,操做數據庫:ide
public class Dao { private static Log logger = LogFactory.getLog(Dao.class); /** * 查詢全部 * @param sql * @param c * @return */ public static<T> List<T> queryAll(String sql,Class<T> c){ Connection connection=null; PreparedStatement pStatement=null; ResultSet rSet=null; List<T> list=new ArrayList<T>(); try { connection=ConnUtil.getConn(); pStatement=connection.prepareStatement(sql); rSet=pStatement.executeQuery(); while(rSet.next()){ //經過反射賦值 T t=c.newInstance(); //獲取全部屬性 Field[] fields=c.getDeclaredFields(); //便利屬性並賦值 for(Field f:fields){ //獲取屬性名 String fName=f.getName(); //獲取屬性值 Object objValue=rSet.getObject(fName); //給屬性設置值 Method method=c.getMethod(setter(fName), f.getType()); method.invoke(t, objValue); } list.add(t); } } catch (SQLException e) { logger.error("數據庫異常:"+e.getMessage(),e); }catch (InstantiationException | IllegalAccessException e1 ){ logger.error("反射異常:"+e1.getMessage(),e1); } catch (NoSuchMethodException e) { logger.error("方法錯誤:"+e.getMessage(),e); } catch (SecurityException e) { logger.error("安全異常:"+e.getMessage(),e); } catch (IllegalArgumentException e) { logger.error("非法轉換異常:"+e.getMessage(),e); } catch (InvocationTargetException e) { logger.error("InvocationTargetException異常:"+e.getMessage(),e); }finally{ ConnUtil.close(rSet,pStatement,connection); } return list; } /** * 條件查詢 * @param sql * @param c * @return */ public static<T> List<T> queryByCondition(String sql,Class<T> c,Object...objects){ Connection connection=null; PreparedStatement pStatement=null; ResultSet rSet=null; List<T> list=new ArrayList<T>(); try { connection=ConnUtil.getConn(); pStatement=connection.prepareStatement(sql); if(objects!=null){ for(int i=0;i<objects.length;i++){ pStatement.setObject(i+1, objects[i]); } } rSet=pStatement.executeQuery(); ResultSetMetaData resultSetMetaData=rSet.getMetaData(); int count=resultSetMetaData.getColumnCount(); while(rSet.next()){ //經過反射賦值 T t=c.newInstance(); for (int i = 0; i < count; i++) { //獲取屬性名 String fName=resultSetMetaData.getColumnName(i); //獲取全部屬性 Field field=c.getDeclaredField(fName); //給屬性設置值 Method method=c.getMethod(setter(fName), field.getType()); //獲取屬性值 Object objValue=rSet.getObject(fName); method.invoke(t, objValue); } list.add(t); } } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); }finally{ ConnUtil.close(rSet,pStatement,connection); } return list; } /** * 更新操做,包括 insert delete update * @param sql * @param objects * @return flag */ public static boolean update(String sql,Object...objects){ Connection connection=null; PreparedStatement pStatement=null; boolean flag=false; try { connection=ConnUtil.getConn(); pStatement=connection.prepareStatement(sql); if(objects!=null){ for(int i=0;i<objects.length;i++){ pStatement.setObject(i+1, objects[i]); } } flag=pStatement.execute(); } catch (SQLException e) { e.printStackTrace(); }finally{ ConnUtil.close(pStatement,connection); } return flag; } private static String setter(String name){ return "set"+name.substring(0,1).toUpperCase()+name.substring(1); } }
JDBC操做數據庫,看似簡單,可是細節不少,須要咱們本身管理數據鏈接,稍不當心會出現鏈接未關閉的狀況,這樣會浪費系統的資源,爲了不咱們本身管理JDBC,因此出現了不少框架,如Mybatis、hibernate這種ORM持久性框架,他們對JDBC作了很好的封裝,另外有Spring框架的支持,不須要咱們去額外維護數據庫的鏈接,咱們能夠把所有精力放在業務的實現上面,可是JDBC是咱們必須會的一個很是重要的知識點,熟悉了JDBC的原理,才能更好的理解框架的應用。以上是在學習和作項目過程當中總結的幾種JDBC用法各有優缺點,但願能對你們的學習有所幫助。性能