JDBC
JDBC(Java DataBase Connectivity)是Java和數據庫之間的一個橋梁,是一個規范而不是一個實現,能夠執行SQL語句。它由一組用Java語言編寫的類和接口組成。各種不同類型的數據庫都有相應的實現。
JDBC規范采用接口和實現分離的思想設計了Java數據庫編程的框架。接口包含在java.sql及 javax.sql包中,其中java.sql屬於JavaSE,javax.sql屬於JavaEE。
為了使客戶端程序獨立於特定的數據庫驅動程序,JDBC規范建議開發者使用基於接口的編程方式,即盡量使應用僅依賴java.sql及javax.sql中的接口和類。
一個例子:

1 Connection conn = null; 2 Statement stmt = null; 3 try { 4 // 注冊 JDBC 驅動 5 Class.forName("com.mysql.jdbc.Driver"); 6 7 // 創建鏈接 8 conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/push_system_new?characterEncoding=UTF-8", "root", "123456"); 9 10 // 執行查詢 11 stmt = conn.createStatement(); 12 String sql = "SELECT id, app_id, device_token FROM push_device_0"; 13 ResultSet rs = stmt.executeQuery(sql); 14 15 while (rs.next()) { 16 // 通過字段檢索 17 long id = rs.getLong("id"); 18 long appId = rs.getLong("app_id"); 19 String deviceToken = rs.getString("device_token"); 20 21 // 輸出數據 22 System.out.print("device_id: " + id); 23 System.out.print(", appId: " + appId); 24 System.out.print(", device_token: " + deviceToken); 25 System.out.print("\n"); 26 break; 27 } 28 29 // 完成后關閉 30 rs.close(); 31 stmt.close(); 32 conn.close(); 33 34 } catch(SQLException se) { 35 // 處理 JDBC 錯誤 36 se.printStackTrace(); 37 38 } catch(Exception e) { 39 // 處理 Class.forName 錯誤 40 e.printStackTrace(); 41 42 } finally { 43 // 關閉資源 44 try { 45 if (stmt != null) stmt.close(); 46 } catch(SQLException se2) { 47 48 } 49 50 // 什么都不做 51 try { 52 if (conn != null) conn.close(); 53 } catch(SQLException se) { 54 se.printStackTrace(); 55 } 56 }
JDBC主要接口:
- Driver接口
- Connection接口,主要方法:
- createStatement(),創建向數據庫發送sql的statement對象;
- prepareStatement(sql),創建向數據庫發送預編譯sql的prepareStatement對象;
- prepareCall(sql),創建執行存儲過程的callableStatement對象;
- setAutoCommit(boolean autoCommit)
- commit()
- rollback()
- Statement接口,主要方法:
- execute(sql),運行sql,返回是否有結果集;
- executeQuery(sql),運行select操作,返回ResultSet結果集;
- executeUpdate(sql),運行insert/update/delete操作,返回更新的行數;
- addBatch(sql),把多條sql語句放到一個批處理中;
- executeBatch(sql),向數據庫發送一批sql語句執行;
- ResultSet接口,主要方法:
- getString(int index)、getString(String columnName),獲取varchar、char類型字段;
- getFloat(int index)、getFloat(String columnName),獲取float類型字段;
- getBoolean(int index)、getBoolean(String columnName),獲取bool類型字段;
- getDate(int index)、getDate(String columnName),獲取Date類型字段;
- next(),移動到下一行;
- previous(),移動到上一行;
- absolute(int row),移動到指定行;
- beforeFirst(),移動到最前面;
- afterLast(),移動到最后;
Datasource
DataSource表示一種創建Connection的工廠,在jdk 1.4引入,相對DriverManager的方式更優先推薦使用DataSource。支持三種實現類型:
- 基本實現:產生一個標准連接對象
- 連接池實現:將連接對象池化處理,由一個連接池管理中間件支持
- 分布式事務實現:支持分布式事務,通常也是池化的,由一個事務管理中間件支持。
基於DataSource產生了兩個非常常用的數據庫連接池框架:DBCP和C3P0,解決了數據庫連接的復用問題,極大地提高了數據庫連接的使用性能。
看一個DBCP的簡單用例,bean配置:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/push_system_new"/> <property name="username" value="root"/> <property name="password" value="123456"/> <property name="initialSize" value="5"/> <property name="maxActive" value="30"/> <property name="maxIdle" value="5"/> <property name="minIdle" value="2"/> </bean>
pom.xml 依賴
<dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency>
JDBCTemplate
JdbcTemplate是Spring框架自帶的對JDBC操作的封裝,目的是提供統一的模板方法使對數據庫的操作更加方便、友好,效率也不錯。但是功能還是不夠強大(比如不支持級聯屬性),在實際應用中還需要和hibernate、mybaties等框架混合使用。
要使用JDBCTemplate對象來完成JDBC操作。通常情況下,有三種種方式得到JDBCTemplate對象。
-
我們可以在自己定義的DAO 實現類中注入一個DataSource 引用來完 成JdbcTemplate 的實例化。也就是它是從外部“注入” DataSource 到DAO 中,然后 自己實例化JdbcTemplate,然后將DataSource 設置到JdbcTemplate 對象中。
-
在 Spring 的 IoC 容器中配置一個 JdbcTemplate 的 bean,將 DataSource 注入進來,然后再把JdbcTemplate 注入到自定義DAO 中。
-
spring 提供了 org.springframework.jdbc.core.support.JdbcDaoSupport 類 , 這 個 類 中 定 義 了 JdbcTemplate 屬性,也定義了DataSource 屬性,當設置DataSource 屬性的時候,會創 建jdbcTemplate 的實例,所以我們自己編寫的DAO 只需要繼承JdbcDaoSupport 類, 然后注入DataSource 即可
public class pushDeviceDaoImpl { private JdbcTemplate jdbcTemplate; public List<DeviceInfo> query(long appId) { String sql = "select * from push_device_0 where app_id=? "; return jdbcTemplate.query(sql, new DeviceRowMapper(), appId); } @Data class DeviceInfo { long app_id; long id; String device_token; } class DeviceRowMapper implements RowMapper<DeviceInfo> { public DeviceInfo mapRow(ResultSet rs, int rowNum) throws SQLException { DeviceInfo deviceInfo = new DeviceInfo(); deviceInfo.setId(rs.getLong("id")); deviceInfo.setApp_id(rs.getLong("app_id")); deviceInfo.setDevice_token(rs.getString("device_token")); return deviceInfo; } } public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } }
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name = "dataSource" ref="dataSource"/> </bean> <bean id="pushDeviceDao" class="com.example.demo.pushDeviceDaoImpl"> <property name="jdbcTemplate" ref="jdbcTemplate"/> </bean>
方法2、
public class pushDeviceDaoImpl { private JdbcTemplate jdbcTemplate; public List<DeviceInfo> query(long appId) { String sql = "select * from push_device_0 where app_id=? "; return jdbcTemplate.query(sql, new DeviceRowMapper(), appId); } @Data class DeviceInfo { long app_id; long id; String device_token; } class DeviceRowMapper implements RowMapper<DeviceInfo> { public DeviceInfo mapRow(ResultSet rs, int rowNum) throws SQLException { DeviceInfo deviceInfo = new DeviceInfo(); deviceInfo.setId(rs.getLong("id")); deviceInfo.setApp_id(rs.getLong("app_id")); deviceInfo.setDevice_token(rs.getString("device_token")); return deviceInfo; } } public void setDataSource(DataSource dataSource) { this.jdbcTemplate = new JdbcTemplate(dataSource); } }
xml中的bean配置:
<bean id="pushDeviceDao" class="com.example.demo.pushDeviceDaoImpl"> <property name="dataSource" ref="dataSource"/> </bean>
public class pushDeviceDaoImpl extends JdbcDaoSupport { @Data class DeviceInfo { long app_id; long id; String device_token; } public List<DeviceInfo> query(long appId) { String sql = "select * from push_device_0 where app_id=? "; return getJdbcTemplate().query(sql, new DeviceRowMapper(), appId); } public List<DeviceInfo> queryToken(long appId, String deviceToken) { String sql = "select * from push_device_23 where app_id=? and device_token=?"; PreparedStatementSetter pss = new PreparedStatementSetter() { public void setValues(PreparedStatement preparedStatement) throws SQLException { preparedStatement.setLong(1, appId); preparedStatement.setString(2, deviceToken); } }; ResultSetExtractor rse = new ResultSetExtractor<List<DeviceInfo>>() { public List<DeviceInfo> extractData(ResultSet rs) throws SQLException, DataAccessException { List<DeviceInfo> list = new ArrayList<>(); while (rs.next()) { DeviceInfo deviceInfo = new DeviceInfo(); deviceInfo.setId(rs.getLong("id")); deviceInfo.setApp_id(rs.getLong("app_id")); deviceInfo.setDevice_token(rs.getString("device_token")); list.add(deviceInfo); } return list; } }; return (List<DeviceInfo>) getJdbcTemplate().query(sql, pss, rse); } class DeviceRowMapper implements RowMapper<DeviceInfo> { public DeviceInfo mapRow(ResultSet rs, int rowNum) throws SQLException { DeviceInfo deviceInfo = new DeviceInfo(); deviceInfo.setId(rs.getLong("id")); deviceInfo.setApp_id(rs.getLong("app_id")); deviceInfo.setDevice_token(rs.getString("device_token")); return deviceInfo; } } }
這里用到了 ResultSetExtractor 接口,該接口的實現執行從ResultSet
提取結果的實際工作,不需要擔心異常處理,它調用JdbcTemplate
捕獲並處理SQLExceptions。 該接口主要用於JDBC框架本身。 RowMapper
通常是ResultSet
處理的簡單選擇查詢,每行映射一個結果對象,而不是整個ResultSet
的一個結果對象。
xml中的bean配置:
<bean id="pushDeviceDao" class="com.example.demo.pushDeviceDaoImpl"> <property name="dataSource" ref="dataSource"/> </bean>
JdbcTemplate主要提供下列方法:
1、execute方法:可以用於執行任何SQL語句,一般用於執行DDL語句;
2、update方法及batchUpdate方法:update方法用於執行新增、修改、刪除等語句;batchUpdate方法用於執行批處理相關語句;
3、query方法及queryForXXX方法:用於執行查詢相關語句;
4、call方法:用於執行存儲過程、函數相關語句。
examples :
getJdbcTemplate().update("insert into user values(?,?,?)", user.getId(), user.getUsername(), user.getPassword()); getJdbcTemplate().update("delete from user where id=?", id); getJdbcTemplate().update("update user set username=?,password=? where id=?", user.getUsername(), user.getPassword(), user.getId()); getJdbcTemplate().queryForObject("select username from user where id=?", String.class, id); // 簡單查詢,返回原始數據類型 getJdbcTemplate().queryForInt("select count(*) from user"); // 簡單查詢,返回原始數據類型 getJdbcTemplate().queryForObject("select * from user where id=?", new UserRowMapper(), id); // 查詢單個對象 getJdbcTemplate().query("select * from user", new UserRowMapper()); // 查詢對象集合