元數據的使用
1)想取得對數據庫相關信息的描述,可以元數據
2)DatabaseMetaData/DatabaseMetaData dbmd =conn.getMetaData()
3)ParameterMetaData/ParameterMetaData psmd =pstmt.getParameterMetaData();
4)ResultSetMetaData/ResultSetMetaData rsmd =rs.getMetaData();
l 元數據:數據庫、表、列的定義信息。
l Connection.getDatabaseMetaData()
l DataBaseMetaData對象
• getURL():返回一個String類對象,代表數據庫的URL。
• getUserName():返回連接當前數據庫管理系統的用戶名。
• getDatabaseProductName():返回數據庫的產品名稱。
• getDatabaseProductVersion():返回數據庫的版本號。
• getDriverName():返回驅動驅動程序的名稱。
• getDriverVersion():返回驅動程序的版本號。
• isReadOnly():返回一個boolean值,指示數據庫是否只允許讀操作。
l PreparedStatement.getParameterMetaData()
• 獲得代表PreparedStatement元數據的ParameterMetaData對象。
l ParameterMetaData對象
• getParameterCount()
l 獲得指定參數的個數
l ResultSet.getMetaData()
• 獲得代表ResultSet對象元數據的ResultSetMetaData對象。
l ResultSetMetaData對象
• getColumnCount()
• 返回resultset對象的列數
• getColumnName(int column)
• 獲得指定列的名稱
• getColumnTypeName(int column)
• 獲得指定列的類型(Types類)
l 業務背景:系統中所有實體對象都涉及到基本的CRUD操作:
• 所有實體的CUD操作代碼基本相同,僅僅發送給數據庫的SQL語句不同而已,因此可以把CUD操作的所有相同代碼抽取到工具類的一個update方法中,並定義參數接收變化的SQL語句。
使用到的數據表:
reatetable if notexistsuser(
id intprimarykey auto_increment,
username varchar(20) notnull,
password varchar(6) notnull,
birthday datenotnull,
salary float
);
元數據實現代碼:
c3p0配置文件:
<?xml version="1.0"encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/mydb2</property>
</default-config>
</c3p0-config>
jdbc工具類
package cn.itcast.web.jdbc.util;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
importcom.mchange.v2.c3p0.ComboPooledDataSource;
//JDBC工具類:關閉流和取得連接
public final class JdbcUtil {
privatestatic ComboPooledDataSource dataSource;
static{
dataSource= new ComboPooledDataSource();
}
//取得數據源
publicstatic ComboPooledDataSource getDataSource() {
returndataSource;
}
//取得連接
publicstatic Connection getMySqlConnection() throws SQLException{
return dataSource.getConnection();
}
//關閉連接
publicstatic void close(Connection conn) throws SQLException{
if(conn!=null){
conn.close();
}
}
publicstatic void close(PreparedStatement pstmt) throws SQLException {
if(pstmt!=null){
pstmt.close();
}
}
publicstatic void close(ResultSet rs) throws SQLException {
if(rs!=null){
rs.close();
}
}
}
元數據的三種用法:
//演示三種元數據庫的用法
publicclass Demo1 {
publicstaticvoid main(String[] args) throws Exception {
Connection conn = JdbcUtil.getMySqlConnection();
String sql = "select *from user";
PreparedStatement pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery();
//取得結果集的相關元數據
ResultSetMetaData rsmd = rs.getMetaData();
int size = rsmd.getColumnCount();
for(int i=0;i<size;i++){
//取得每列的列名
String columnName = rsmd.getColumnName(i+1);
//取得每列的類型
int typeCode = rsmd.getColumnType(i+1);
System.out.println(columnName+":"+typeCode);
}
/*取是有關SQL的相關元數據
String sql = "insert into user(username,password,birthday,salary)values(?,?,?,?)";
ParameterMetaData psmd = pstmt.getParameterMetaData();
int size = psmd.getParameterCount();
System.out.println("共有" + size+"個參數");
*/
//取得DataBaseMetaData
DatabaseMetaData dbmd = conn.getMetaData();
String driver = dbmd.getDriverName();//驅動名
String url = dbmd.getURL();//連接url
int level = dbmd.getDefaultTransactionIsolation();//事務隔離級別
String productName = dbmd.getDatabaseProductName();//產品名稱
boolean flag = dbmd.isReadOnly();//是否只讀
System.out.println("flag="+flag);
System.out.println("driver="+driver);
System.out.println("url="+url);
System.out.println("level="+level);
System.out.println("productName="+productName);
}
使用元數據進行CURD操作
/使用元數據+反射優化CURD操作
publicclass Demo2 {
publicstaticvoid main(String[] args) throws Exception {
/*
* 插入
String sql = "insert into user(username,password,birthday,salary)values(?,?,?,?)";
Object[] params = {"sisi","000000","2011-10-28",5000};
update(sql, params);
*/
/*
* 更新
String sql = "update user set username=?where username=?";
Object[] params = {"shashan","sisi"};
update(sql, params);
*/
/*
//刪除
String sql = "delete from user where id = ?";
update(sql,new Object[]{2});
*/
/*
* 查詢
String sql = "select * from user where id =?";
User user = (User) query(sql,newObject[]{1},User.class);
System.out.println("用戶名:" + user.getUsername());
System.out.println("密碼:" + user.getPassword());
System.out.println("生日:" + user.getBirthday().toLocaleString());
System.out.println("薪水:" + user.getSalary());
*/
}
//R操作(通用的方法)
publicstatic Object query(String sql,Object[] params,Classclazz) throws Exception {
Object obj = clazz.newInstance();
Connection conn = JdbcUtil.getMySqlConnection();
PreparedStatement pstmt = conn.prepareStatement(sql);
ParameterMetaData psmd = pstmt.getParameterMetaData();
int size = psmd.getParameterCount();
for(int i=0;i<size;i++){
pstmt.setObject(i+1,params[i]);
}
ResultSet rs = pstmt.executeQuery();
if(rs.next()){
//取得結果集元數據
ResultSetMetaData rsmd = rs.getMetaData();
//取得結果集列數目
size = rsmd.getColumnCount();
//以列值爲單位,設置到JavaBean中去
for(int i=0;i<size;i++){
//取得列名
String columnName = rsmd.getColumnName(i+1);
//通過BeanUtils框架爲JavaBean設置值
BeanUtils.setProperty(obj,columnName,rs.getObject(i+1));
}
}
JdbcUtil.close(rs);
JdbcUtil.close(pstmt);
JdbcUtil.close(conn);
return obj;
}
//CUD操作(通用的方法)
publicstaticvoid update(String sql,Object[] params) throws SQLException {
Connection conn = JdbcUtil.getMySqlConnection();
PreparedStatement pstmt = conn.prepareStatement(sql);
//取得參數元數據
ParameterMetaData psmd = pstmt.getParameterMetaData();
//取得參數的個數
int size = psmd.getParameterCount();
//循環綁定對象的值
for(int i=0;i<size;i++){
pstmt.setObject(i+1,params[i]);
}
//執行
pstmt.executeUpdate();
//關閉對應的連接對象
JdbcUtil.close(conn);
JdbcUtil.close(pstmt);
}
}
l commons-dbutils 是 Apache 組織提供的一個開源 JDBC工具類庫,它是對JDBC的簡單封裝,學習成本極低,並且使用dbutils能極大簡化jdbc編碼的工作量,同時也不會影響程序的性能。因此dbutils成爲很多不喜歡hibernate的公司的首選。
l API介紹:
• org.apache.commons.dbutils.QueryRunner(類)
• org.apache.commons.dbutils.ResultSetHandler(接口)
• 工具類
• org.apache.commons.dbutils.DbUtils。
QueryRunner類
l 該類簡單化了SQL查詢,它與ResultSetHandler組合在一起使用可以完成大部分的數據庫操作,能夠大大減少編碼量。
l QueryRunner類提供了兩個構造方法:
• 默認的構造方法
• 需要一個 javax.sql.DataSource 來作參數的構造方法。
QueryRunner類的主要方法
l public Object query(Connectionconn, String sql, Object[] params, ResultSetHandler rsh) throws SQLException:執行一個查詢操作,在這個查詢中,對象數組中的每個元素值被用來作爲查詢語句的置換參數。該方法會自行處理 PreparedStatement 和 ResultSet 的創建和關閉。
l public Object query(String sql,Object[] params, ResultSetHandler rsh) throws SQLException: 幾乎與第一種方法一樣;唯一的不同在於它不將數據庫連接提供給方法,並且它是從提供給構造方法的數據源(DataSource) 或使用的setDataSource 方法中重新獲得 Connection。
l public Object query(Connectionconn, String sql, ResultSetHandler rsh) throws SQLException : 執行一個不需要置換參數的查詢操作。
l public int update(Connectionconn, String sql, Object[] params) throws SQLException:用來執行一個更新(插入、更新或刪除)操作。
l public int update(Connectionconn, String sql) throws SQLException:用來執行一個不需要置換參數的更新操作。
ResultSetHandler接口
l 該接口用於處理 java.sql.ResultSet,將數據按要求轉換爲另一種形式。
l ResultSetHandler 接口提供了一個單獨的方法:Object handle(java.sql.ResultSet .rs)。
ResultSetHandler接口的實現類
l BeanHandler:將結果集中的第一行數據封裝到一個對應的JavaBean實例中。
l BeanListHandler:將結果集中的每一行數據都封裝到一個對應的JavaBean實例中,存放到List裏。
l ArrayHandler:把結果集中的第一行數據轉成對象數組。
l ArrayListHandler:把結果集中的每一行數據都轉成一個對象數組,再存放到List中。
ResultSetHandler接口的實現類
l MapHandler:將結果集中的第一行數據封裝到一個Map裏,key是列名,value就是對應的值。
l MapListHandler:將結果集中的每一行數據都封裝到一個Map裏,然後再存放到List。
l ScalarHandler:結果集中只有一行一列數據。
DbUtils類
l DbUtils :提供如關閉連接、裝載JDBC驅動程序等常規工作的工具類,裏面的所有方法都是靜態的。主要方法如下:
l public static void close(…)throws java.sql.SQLException: DbUtils類提供了三個重載的關閉方法。這些方法檢查所提供的參數是不是NULL,如果不是的話,它們就關閉Connection、Statement和ResultSet。
l public static voidcloseQuietly(…): 這一類方法不僅能在Connection、Statement和ResultSet爲NULL情況下避免關閉,還能隱藏一些在程序中拋出的SQLException。
l public static voidcommitAndCloseQuietly(Connection conn):用來提交連接,然後關閉連接,並且在關閉連接時不拋出SQL異常。
l public static booleanloadDriver(java.lang.String driverClassName):這一方裝載並註冊JDBC驅動程序,如果成功就返回true。使用該方法,你不需要捕捉這個異常ClassNotFoundException。
* DBUtils框架的使用
1)目的:減化CURD操作
2)DBUtils框架最核心的類,就是QueryRunner類,構造其有二種方式
a)空參構造
b)通過DataSource構造
3)DBUtils對象的update()方法,內部已經關閉相關的連接對象
4)update(Connection)方法帶有Connection對象的,需要手工關閉,其它對象自動關閉
update()方法無Connection對象的,DBUtils框架自動關閉
5)爲什麼作者要這樣設計?
主要考慮了在分層結構中,需要用到同一個Connection的問題
6)對於query()操作與update()操作有着一致的含義
7)對於query()操作的實現類含義如下;
BeanHandler/BeanListHandler:爭對JavaBean
ArrayHandler/ArrayListHandler:爭對數組
MapHandler/MapListHandler:爭對Map
ScalarHandler:爭對Long
DBUTIL
//演示DBUtils框架的使用
publicclass Demo3 {
publicstaticvoid main(String[] args) throws SQLException {
//QueryRunner runner = newQueryRunner(JdbcUtil.getDataSource());
//String sql ="insert into user(username,password,birthday,salary)values(?,?,?,?)";
//String sql ="update user set username=? where username=?";
//String sql ="delete from user where id = ?";
//runner.update(sql,newObject[]{4});
//插入
Connection conn = JdbcUtil.getMySqlConnection();
QueryRunner runner = new QueryRunner();
String sql = "insert intouser(username,password,birthday,salary) values(?,?,?,?)";
runner.update(conn,sql,new Object[]{"tim","111222","2011-10-10",5000});
JdbcUtil.close(conn);
}
}
//演示ResultSetHandler接口的各種實現類的用法
publicclass Demo4 {
@Test
publicvoid testBeanHandler() throws SQLException{
QueryRunner runner = new QueryRunner(JdbcUtil.getDataSource());
String sql = "select *from user";
User user = (User) runner.query(sql,new BeanHandler(User.class));
System.out.println("用戶名:" + user.getUsername());
}
@Test
publicvoid testBeanListHandler() throws SQLException{
QueryRunner runner = new QueryRunner(JdbcUtil.getDataSource());
String sql = "select *from user";
List<User> userList = (List<User>)runner.query(sql,new BeanListHandler(User.class));
for(User user : userList){
System.out.println("用戶名:" + user.getUsername());
System.out.println("密碼:" + user.getPassword());
}
}
@Test
publicvoid testArrayHandler() throws SQLException{
QueryRunner runner = new QueryRunner(JdbcUtil.getDataSource());
String sql = "select *from user";
Object[] array = (Object[]) runner.query(sql,new ArrayHandler());
System.out.println("編號 : " + array[0]);
System.out.println("用戶名 : " + array[1]);
}
@Test
publicvoid testArrayListHandler() throws SQLException{
QueryRunner runner = new QueryRunner(JdbcUtil.getDataSource());
String sql = "select *from user";
List<Object[]> list = (List<Object[]>)runner.query(sql,new ArrayListHandler());
for(Object[] array : list){
System.out.print("編號 : " + array[0] + "\t");
System.out.println("用戶名 : " + array[1]);
}
}
@Test
publicvoid testMapHandler() throws SQLException{
QueryRunner runner = new QueryRunner(JdbcUtil.getDataSource());
String sql = "select *from user";
Map<Object,Object> map = (Map<Object, Object>)runner.query(sql,new MapHandler());
System.out.println("用戶名:" + map.get("username"));
}
@Test
publicvoid testMapListHandler() throws SQLException{
QueryRunner runner = new QueryRunner(JdbcUtil.getDataSource());
String sql = "select *from user";
List<Map<Object,Object>> list = (List<Map<Object,Object>>) runner.query(sql,new MapListHandler());
for(Map<Object,Object> map : list){
System.out.println("用戶名:" + map.get("username"));
System.out.println("薪水:" + map.get("salary"));
}
}
@Test
publicvoid testScalarHandler() throws SQLException{
QueryRunner runner = new QueryRunner(JdbcUtil.getDataSource());
String sql = "selectcount(*) from user";
Long sum = (Long) runner.query(sql,new ScalarHandler());
System.out.println("共有" + sum + "人");
}
}