0基礎之你不知道的JDBC
一、JDBC入門
想要使用JDBC就得有一個資料庫,這裡以mysql為例子。
獲取一個mysql的jar包,複製貼上到該資料夾下,右鍵bulid path安裝到路徑內
然後最基本的操作順序就是載入驅動–>獲取連線–>執行SQL–>釋放資源。例子如下:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import org.junit.Test;
public class JDBCDemo1 {
@Test
public void demo1() throws Exception{
Class.forName("com.mysql.jdbc.Driver");//載入驅動
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db3", "root", "");
//獲得連線
Statement statement = conn.createStatement();//獲得可執行sql的物件
String sql = "show tables";//sql語句
ResultSet rs = statement.executeQuery(sql);//執行sql語句
//遍歷結果集
while (rs.next()) {
System.out.println(rs.getString("Tables_in_db3"));
}
//釋放資源
rs.close();
statement.close();
conn.close();
}
}
二、API詳解和其他基本操作
DriverManager : 驅動管理類
作用:註冊驅動
這個類裡面有一個靜態註冊驅動的方法registerDriver (Driver driver)
這個方法可以完成驅動的註冊,但是實際開發中一般不會使用這個方法完成驅動的註冊!
原因:
如果需要註冊驅動,就會使用DriverManager.registerDriver(new Driver());
但是這個Driver類在程式碼中有一段靜態程式碼塊,靜態程式碼塊已經呼叫了註冊驅動的方法。
如果再手動呼叫則會導致註冊兩次。
所以一般使用Class.forName(“com.mysql.jdbc.Driver”); 去註冊驅動。
作用:獲得與資料庫的連線
用這個方法獲得與資料庫連線:getConnection (String url,String user,String password);
這個裡面url的寫法需要重點關注。入門中的例子裡是這樣的:
jdbc:mysql://localhost:3306/db3
各個的含義是:
jdbc : 連線資料庫的協議
mysql : 是jdbc的子協議
localhost : 連線的MysQL 資料庫伺服器的主機地址。(連線是本機就可以寫成localhost),如果連線不是本機的,就需要寫上連線主機的IP地址。
3306 : MySQL資料庫伺服器的埠號+
db3 : 資料庫名稱
url如果連線的是本機的路徑,可以簡化為如下格式:
jdbc:mysql:///db3;
注意:是3個/
Connection :與資料庫連線物件
作用:建立執行sql語句的物件
createStatement() : 建立一個 Statement物件來將SQL語句傳送到資料庫。
prepareCall(String sql) : 建立一個CallableStatement 物件來呼叫資料庫儲存過程。
prepareStatement(String sql) : 建立一個PreparedStatement物件來將引數化的SQL語句傳送到資料庫。
statement : 執行SQL
Callablestatement : 執行資料庫中儲存過程
PreparedStatement : 執行SQL對SQL進行預處理。解決SQL隱碼攻擊漏洞。
作用:管理事務
setAutoCommit (boolean autoCommit) : 將此連線的自動提交模式設定為給定狀態。
commit() : 使所有上一次提交/回滾後進行的更改成為持久更改,並釋放此Connection物件當前持有的所有資料庫鎖。
rollback() : 取消在當前事務中進行的所有更改,並釋放此Connection物件當前持有的所有資料庫鎖。
Statement : 執行SQL
作用:執行SQL
boolean execute(String sql) :執行給定的SQL語句(該語句可能返回多個結果),並通知驅動程式所有自動生成的鍵都應該可用於獲取。 執行查詢,修改,新增,刪除的SQL語句,如果是查詢語句返回true,如果是修改,新增,刪除的SQL語句,返回false。
一般使用下面兩個方法:
ResultSet executeQuery(String sql) : 執行給定的SQL語句,該語句返回單個ResultSet物件。 執行查詢
int executeUpdate(string sql) : 執行給定SQL語句,該語句可能為INSERT、UPDATE或 DELETE語句,或者不返回任何內容的SQL語句(如SQL DDL語句)。執行修改,新增,刪除的SQL語句
作用:執行批處理
addBatch (String sql) : 將給定的SQL命令新增到此Statement物件的當前命令列表中。
**clearBatch() **: 清空此 Statement 物件的當前SQL命令列表。
int[] executeBatch() : 將一批命令提交給資料庫來執行,如果全部命令執行成功,則返回更新計陣列成的陣列。
ResultSet : 結果集
通過查詢語句獲得的結果。
next() : 這個游標最早是在第一行之前,當呼叫了next()之後就會指向第一行。
那麼結果集的獲取就需要使用getxxx() 方法,如下:
getXxx(int columnlndex); 列號
getXxx(String columnName); 列名,通常是使用這個
資源釋放
JDBC程式執行結束後,將與資料庫進行互動的物件釋放掉,通常ResultSet,Statement,Connection。這幾個物件中尤其是Connection物件是非常稀有的。這個物件一定要做到儘量晚建立,儘早釋放掉。
將資源釋放的程式碼寫入到 finally 的程式碼塊中。
資源釋放的程式碼應該寫的標準:手動置為null的用處是讓gc更早回收
//釋放資源
if (rs!=null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
if (statement!=null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
statement = null;
}
if (conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
CRUD
1.利用statement儲存、修改、刪除、查詢操作:
儲存操作:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import org.junit.Test;
public class JDBCDemo2 {
@Test
public void demo1() {
Connection conn = null;
Statement statement = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc", "root", "");
statement = conn.createStatement();
String sql = new String("insert into user values(null,'小明','10086',18,'1999-01-02')");
int num = statement.executeUpdate(sql);
if (num>0) {
System.out.println("資料儲存成功");
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if (statement!=null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
statement = null;
}
if (conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
}
}
此時去資料庫查詢表可以發現資料已經插入成果!如果出現中文亂碼問題應該是資料庫字符集未設定好,去手動設定一下就OK了。
修改操作:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import org.junit.Test;
public class JDBCDemo2 {
@Test
public void demo1() {
Connection conn = null;
Statement statement = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc", "root", "");
statement = conn.createStatement();
String sql = "update user set username = '小美',password = '110',age=20,birthday='1999-12-05' where id = 1";
int num = statement.executeUpdate(sql);
if (num>0) {
System.out.println("資料更新成功");
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if (statement!=null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
statement = null;
}
if (conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
}
}
執行結果查詢資料庫如下圖:
刪除操作:
@Test
public void demo2() {
Connection conn = null;
Statement statement = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc", "root", "");
statement = conn.createStatement();
String sql = "delete from user where id = 2";
int num = statement.executeUpdate(sql);
if (num>0) {
System.out.println("資料刪除成功");
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if (statement!=null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
statement = null;
}
if (conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
}
執行結果查詢資料庫如下圖:
查詢操作:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.junit.Test;
public class JDBCDemo2 {
@Test
public void demo1() {
Connection conn = null;
Statement statement = null;
ResultSet rs = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc", "root", "");
statement = conn.createStatement();
String sql = "select * from user";
rs = statement.executeQuery(sql);
while (rs.next()) {
System.out.println(rs.getInt("id")+" "+rs.getString("username")+" "+rs.getString("password")+" "+rs.getInt("age")+" "+rs.getString("birthday"));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if (rs!=null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
if (statement!=null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
statement = null;
}
if (conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
}
}
程式執行結果如下:
2.工具類的抽取
寫出上述程式碼後發現,程式碼重複且無趣,於是可以編寫一個工具類方便書寫,程式碼如下:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCUtils {
private static final String driverClassName;
private static final String url;
private static final String username;
private static final String password;
static {
driverClassName = "com.mysql.jdbc.Driver";
url = "jdbc:mysql:///jdbc";
username = "root";
password = "";
}
public static void loadDriver() {
try {
Class.forName(driverClassName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() {
Connection conn = null;
try {
loadDriver();
conn = DriverManager.getConnection(url,username,password);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
public static void release(ResultSet rs,Statement statement,Connection conn) {
if (rs!=null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
if (statement!=null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
statement = null;
}
if (conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
public static void release(Statement statement,Connection conn) {
if (statement!=null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
statement = null;
}
if (conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
}
以後就可以利用自己的工具類去編寫程式。
2.1配置資訊提取到配置檔案
配置檔案有兩種,屬性檔案和XML
本文采用屬性檔案
檔案格式 : 副檔名是properties
內容: key=values
如下圖:
有了配置檔案後,就可以在檔案中修改,那麼修改上述我們建立的工具類中static的靜態程式碼塊中的部分就可以了。
static {
Properties properties = new Properties();
try {
properties.load(new FileInputStream("src/db.properties"));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
driverClassName = properties.getProperty("driverClassName");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
}
3.sql注入漏洞
sql注入漏洞就是不知道你密碼,但是知道使用者名稱也可以登入你的賬戶,下面寫一個簡單的登入程式,演示這一個漏洞
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import com.jdbc.utils.JDBCUtils;
public class UserDemo {
private boolean login(String username,String password) {
Connection conn= null;
Statement statement= null;
ResultSet rs= null;
boolean flag = false;
try {
conn = JDBCUtils.getConnection();
statement = conn.createStatement();
String sql = "select * from user where username = '"+username+"'and password = '"+password+"'";
rs = statement.executeQuery(sql);
if (rs.next()) {
flag = true;
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtils.release(rs, statement, conn);
}
return flag;
}
}
乍一看是沒有問題,實際上只需要
輸入使用者名稱 aaa' or '1=1 或者 aaa' --
密碼 隨意
就可以登入aaa的賬戶,這就是sql注入漏洞
那麼如何解決呢?
其實產生這個漏洞的原因是因為使用者名稱使用了sql的關鍵字造成的
那麼我們只需要採用 PreparedStatement 物件解決SQL隱碼攻擊漏洞。這個物件將SQL預先進行編譯,使用?作為佔位符。?所代表內容是SQL所固定。再次傳入變數(包含SQL的關鍵字)。這個時候也不會識別這些關鍵字。程式碼如下:
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import com.jdbc.utils.JDBCUtils;
public class UserDemo {
private boolean login(String username,String password) {
Connection conn= null;
PreparedStatement pStatement = null;
ResultSet rs= null;
boolean flag = false;
try {
conn = JDBCUtils.getConnection();
String sql = "select * from user where username = ? and password = ?";
pStatement = conn.prepareStatement(sql);
pStatement.setString(1, username);
pStatement.setString(2, password);
rs = pStatement.executeQuery();
if (rs.next()) {
flag = true;
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtils.release(rs, pStatement, conn); //pStatement 是 statement的子介面,所以利用了多型,可以釋放
}
return flag;
}
}
4.利用PreparedStatement儲存、修改、刪除、查詢操作:
儲存:
import java.sql.Connection;
import java.sql.PreparedStatement;
import org.junit.Test;
import com.jdbc.utils.JDBCUtils;//自己寫的工具類
public class JDBCDemo {
@Test
public void demo() {
Connection conn = null;
PreparedStatement pStatement = null;
try {
conn = JDBCUtils.getConnection();
String sql = "insert into user values(?,?,?,?,?)";
pStatement = conn.prepareStatement(sql);
pStatement.setInt(1, 2);
pStatement.setString(2, "小趙");
pStatement.setString(3, "123456");
pStatement.setInt(4, 19);
pStatement.setString(5, "2001-01-01");
int num = pStatement.executeUpdate();
if (num>0) {
System.out.println("插入成功");
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtils.release(pStatement, conn);
}
}
}
修改:
import java.sql.Connection;
import java.sql.PreparedStatement;
import org.junit.Test;
import com.jdbc.utils.JDBCUtils;
public class JDBCDemo {
@Test
public void demo() {
Connection conn = null;
PreparedStatement pStatement = null;
try {
conn = JDBCUtils.getConnection();
String sql = "update user set password = ? where id = ?";
pStatement = conn.prepareStatement(sql);
pStatement.setString(1, "987654");
pStatement.setInt(2, 1);
int num = pStatement.executeUpdate();
if (num>0) {
System.out.println("修改成功");
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtils.release(pStatement, conn);
}
}
}
刪除:
import java.sql.Connection;
import java.sql.PreparedStatement;
import org.junit.Test;
import com.jdbc.utils.JDBCUtils;
public class JDBCDemo {
@Test
public void demo() {
Connection conn = null;
PreparedStatement pStatement = null;
try {
conn = JDBCUtils.getConnection();
String sql = "delete from user where id = ?";
pStatement = conn.prepareStatement(sql);
pStatement.setInt(1, 3);
int num = pStatement.executeUpdate();
if (num>0) {
System.out.println("刪除成功");
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtils.release(pStatement, conn);
}
}
}
查詢:
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import org.junit.Test;
import com.jdbc.utils.JDBCUtils;
public class JDBCDemo {
@Test
public void demo() {
Connection conn = null;
PreparedStatement pStatement = null;
ResultSet rs = null;
try {
conn = JDBCUtils.getConnection();
String sql = "select * from user";
pStatement = conn.prepareStatement(sql);
rs = pStatement.executeQuery(sql);
while(rs.next()) {
System.out.println(rs.getInt("id")+" "+rs.getString("username")+" "+rs.getString("password")+" "+rs.getInt("age")+" "+rs.getString("birthday"));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtils.release(rs,pStatement, conn);
}
}
}
批處理
批處理在預設情況下是關閉的,需要再url後面新增上 ?rewriteBatchedStatements=true 如下圖:
批處理適合那種重複的插入視情況而看。下列是一個插入多個引數的例子:
import java.sql.Connection;
import java.sql.PreparedStatement;
import org.junit.Test;
import com.jdbc.utils.JDBCUtils;
public class JDBCDemo5 {
@Test
public void demo() {
long begin = System.currentTimeMillis();//測試耗時
Connection conn = null;
PreparedStatement pStatement = null;
try {
conn = JDBCUtils.getConnection();
String sql = "insert into user values(null,?,?,?,?)";
pStatement = conn.prepareStatement(sql);
for (int i = 1; i <= 1000; i++) {
pStatement.setString(1,"name"+i);
pStatement.setString(2,i+"");
pStatement.setInt(3,i);
pStatement.setString(4, "1999-01-01");
pStatement.addBatch();
if (i%100==0) {
pStatement.executeBatch();
pStatement.clearBatch();
}
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtils.release(pStatement, conn);
}
long end = System.currentTimeMillis();
System.out.println("耗時(秒):"+(end-begin)/1000);
}
}
此圖僅僅展示部分
JDBC的事務管理
就是一組邏輯,要麼一起成功要麼一起失敗,首先先在資料庫中建立一個賬目表,如下:
use jdbc;
create table account(
id int primary key auto_increment,
name varchar(20),
money double
);
insert into account values(null,'aaa',10000);
insert into account values(null,'bbb',10000);
insert into account values(null,'ccc',10000);
在轉賬中沒有新增事務的管理,假如轉賬時候出現異常,會出現 aaa賬號的錢被轉丟了,但是 bbb.賬號的錢沒有任何變化。需要給轉賬的功能新增事務的管理。程式碼如下:
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.junit.Test;
import com.jdbc.utils.JDBCUtils;
public class TransactionDemo1 {
@Test
public void demo1() {
Connection conn = null;
PreparedStatement pStatement = null;
try {
conn = JDBCUtils.getConnection();
conn.setAutoCommit(false);
String sql = "update account set money = money + ? where name = ?";
pStatement = conn.prepareStatement(sql);
pStatement.setDouble(1, -1000);
pStatement.setString(2, "aaa");
pStatement.executeUpdate();
/*假如這裡有個異常,資料庫的資料就不會發生變化,因為沒提交,被回滾了*/
pStatement.setDouble(1, 1000);
pStatement.setString(2, "bbb");
pStatement.executeUpdate();
conn.commit();
} catch (Exception e) {
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally {
JDBCUtils.release(pStatement, conn);
}
}
}
三、連線池
連線池是建立和管理一個連線的緩衝池的技術,這些連線準備好被任何需要它們的執行緒使用。連線池是裝有連線的容器,使用連線的話,可以從連線池中進行獲取,使用完成之後將連線歸還給連線池。
作用:連線物件建立和銷燬是需要耗費時間的,在伺服器初始化的時候就初始化一些連線。把這些連線放入到記憶體中,使用的時候可以從記憶體中獲取,使用完成之後將連線放入連線池中。從記憶體中獲取和歸還的效率要遠遠高於建立和銷燬的效率。(提升效能)。
自定義連線池的實現
1.步驟:
1.編寫一個類實現DataSource
2.重寫getConnection方法
3.初始化多個連線在記憶體中
4.編寫歸還連線的方法
第一個例子:
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import javax.sql.DataSource;
import com.jdbc.utils.JDBCUtils;
public class MyDataSource implements DataSource {
public List<Connection> connList = new ArrayList<Connection>();
//初始化提供連線
public MyDataSource(){
for (int i = 1; i <= 3; i++) {
connList.add(JDBCUtils.getConnection());
}
}
//從連線池獲得連線
@Override
public Connection getConnection() throws SQLException {
return connList.remove(0);
}
//編寫一個歸還連線的方法
public void addBack(Connection conn) {
connList.add(conn);
}
//下列程式碼不用管
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
// TODO Auto-generated method stub
return null;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
// TODO Auto-generated method stub
return false;
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public PrintWriter getLogWriter() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public int getLoginTimeout() throws SQLException {
// TODO Auto-generated method stub
return 0;
}
}
測試:
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.junit.Test;
public class DataSourceDemo {
@Test
public void demo1() {
Connection conn = null;
PreparedStatement pStatement = null;
ResultSet rs = null;
MyDataSource dataSource = null;
try {
dataSource = new MyDataSource();
conn = dataSource.getConnection();
String sql = "select * from account";
pStatement = conn.prepareStatement(sql);
rs = pStatement.executeQuery();
while (rs.next()) {
System.out.println(rs.getInt("id")+" "+rs.getString("name")+" "+rs.getDouble("money"));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if (rs!=null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
if (pStatement!=null) {
try {
pStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
pStatement = null;
}
dataSource.addBack(conn);
}
}
}
執行結果如下圖:
說明可以使用自己建立的連線池。雖然可以使用但是還是有很多不足,這種寫法不方便擴充,若使用者想使用還得知道我的連線池的方法,增加了使用者使用的難度。那麼我們可以使用裝飾者模式,對close() 進行增強.
2.利用裝飾者模式對自定義連線池進行優化
裝飾者模式使用條件:
增強雖的類和被增強的類實現相同的介面
在增強的類中獲得被增強的類的引用
裝飾者模式達到對類增強的簡單例子:
interface Waiter{
public void server();
}
class Waitress implements Waiter{
public void server() {
System.out.println("服務中ing");
}
}
class WaitressWrapper implements Waiter{
private Waiter waiter;
public WaitressWrapper(Waiter waiter) {
this.waiter = waiter;
}
public void server() {
System.out.println("微笑");
waiter.server();
}
}
這樣就達到了對server()方法的一個增強,服務中要先一個微笑。利用這種思路,就可以對我們的連線池進行優化。但是缺點很明顯,假設介面需要重寫的方法很多,為了簡化程式設計,可以提供一個模板類(模板類原封不動的將介面中的所有方法都實現,但是都沒有增強)。編寫一個裝飾類繼承模板類。在裝飾類中只需要增強某一個方法即可。
為了編寫方便,我編寫了一個模板類,只需要讓裝飾類繼承模板類然後重寫close方法達到不銷燬,而是歸還的目的。
模板類:
ConnectionWrapper類
package com.datasource.demo1;
import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;
public class ConnectionWrapper implements Connection{
private Connection conn;
public ConnectionWrapper(Connection conn) {
this.conn = conn;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
// TODO Auto-generated method stub
return conn.unwrap(iface);
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
// TODO Auto-generated method stub
return conn.isWrapperFor(iface);
}
@Override
public Statement createStatement() throws SQLException {
// TODO Auto-generated method stub
return conn.createStatement();
}
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
// TODO Auto-generated method stub
return conn.prepareStatement(sql);
}
@Override
public CallableStatement prepareCall(String sql) throws SQLException {
// TODO Auto-generated method stub
return conn.prepareCall(sql);
}
@Override
public String nativeSQL(String sql) throws SQLException {
// TODO Auto-generated method stub
return conn.nativeSQL(sql);
}
@Override
public void setAutoCommit(boolean autoCommit) throws SQLException {
// TODO Auto-generated method stub
conn.setAutoCommit(autoCommit);
}
@Override
public boolean getAutoCommit() throws SQLException {
// TODO Auto-generated method stub
return conn.getAutoCommit();
}
@Override
public void commit() throws SQLException {
// TODO Auto-generated method stub
conn.commit();
}
@Override
public void rollback() throws SQLException {
// TODO Auto-generated method stub
conn.rollback();
}
@Override
public void close() throws SQLException {
// TODO Auto-generated method stub
conn.close();
}
@Override
public boolean isClosed() throws SQLException {
// TODO Auto-generated method stub
return conn.isClosed();
}
@Override
public DatabaseMetaData getMetaData() throws SQLException {
// TODO Auto-generated method stub
return conn.getMetaData();
}
@Override
public void setReadOnly(boolean readOnly) throws SQLException {
// TODO Auto-generated method stub
conn.setReadOnly(readOnly);
}
@Override
public boolean isReadOnly() throws SQLException {
// TODO Auto-generated method stub
return conn.isReadOnly();
}
@Override
public void setCatalog(String catalog) throws SQLException {
// TODO Auto-generated method stub
conn.setCatalog(catalog);
}
@Override
public String getCatalog() throws SQLException {
// TODO Auto-generated method stub
return conn.getCatalog();
}
@Override
public void setTransactionIsolation(int level) throws SQLException {
// TODO Auto-generated method stub
conn.setTransactionIsolation(level);
}
@Override
public int getTransactionIsolation() throws SQLException {
// TODO Auto-generated method stub
return conn.getTransactionIsolation();
}
@Override
public SQLWarning getWarnings() throws SQLException {
// TODO Auto-generated method stub
return conn.getWarnings();
}
@Override
public void clearWarnings() throws SQLException {
// TODO Auto-generated method stub
conn.clearWarnings();
}
@Override
public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
// TODO Auto-generated method stub
return conn.createStatement(resultSetType, resultSetConcurrency);
}
@Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
throws SQLException {
// TODO Auto-generated method stub
return conn.prepareStatement(sql, resultSetType, resultSetConcurrency);
}
@Override
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
// TODO Auto-generated method stub
return conn.prepareCall(sql, resultSetType, resultSetConcurrency);
}
@Override
public Map<String, Class<?>> getTypeMap() throws SQLException {
// TODO Auto-generated method stub
return conn.getTypeMap();
}
@Override
public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
// TODO Auto-generated method stub
conn.setTypeMap(map);
}
@Override
public void setHoldability(int holdability) throws SQLException {
// TODO Auto-generated method stub
conn.setHoldability(holdability);
}
@Override
public int getHoldability() throws SQLException {
// TODO Auto-generated method stub
return conn.getHoldability();
}
@Override
public Savepoint setSavepoint() throws SQLException {
// TODO Auto-generated method stub
return conn.setSavepoint();
}
@Override
public Savepoint setSavepoint(String name) throws SQLException {
// TODO Auto-generated method stub
return conn.setSavepoint(name);
}
@Override
public void rollback(Savepoint savepoint) throws SQLException {
// TODO Auto-generated method stub
conn.rollback();
}
@Override
public void releaseSavepoint(Savepoint savepoint) throws SQLException {
// TODO Auto-generated method stub
conn.releaseSavepoint(savepoint);
}
@Override
public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability)
throws SQLException {
// TODO Auto-generated method stub
return conn.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
}
@Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency,
int resultSetHoldability) throws SQLException {
// TODO Auto-generated method stub
return conn.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
}
@Override
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency,
int resultSetHoldability) throws SQLException {
// TODO Auto-generated method stub
return conn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
}
@Override
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
// TODO Auto-generated method stub
return conn.prepareStatement(sql, autoGeneratedKeys);
}
@Override
public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
// TODO Auto-generated method stub
return conn.prepareStatement(sql, columnIndexes);
}
@Override
public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
// TODO Auto-generated method stub
return conn.prepareStatement(sql, columnNames);
}
@Override
public Clob createClob() throws SQLException {
// TODO Auto-generated method stub
return conn.createClob();
}
@Override
public Blob createBlob() throws SQLException {
// TODO Auto-generated method stub
return conn.createBlob();
}
@Override
public NClob createNClob() throws SQLException {
// TODO Auto-generated method stub
return conn.createNClob();
}
@Override
public SQLXML createSQLXML() throws SQLException {
// TODO Auto-generated method stub
return conn.createSQLXML();
}
@Override
public boolean isValid(int timeout) throws SQLException {
// TODO Auto-generated method stub
return conn.isValid(timeout);
}
@Override
public void setClientInfo(String name, String value) throws SQLClientInfoException {
// TODO Auto-generated method stub
conn.setClientInfo(name, value);
}
@Override
public void setClientInfo(Properties properties) throws SQLClientInfoException {
// TODO Auto-generated method stub
conn.setClientInfo(properties);
}
@Override
public String getClientInfo(String name) throws SQLException {
// TODO Auto-generated method stub
return conn.getClientInfo(name);
}
@Override
public Properties getClientInfo() throws SQLException {
// TODO Auto-generated method stub
return conn.getClientInfo();
}
@Override
public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
// TODO Auto-generated method stub
return conn.createArrayOf(typeName, elements);
}
@Override
public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
// TODO Auto-generated method stub
return conn.createStruct(typeName, attributes);
}
@Override
public void setSchema(String schema) throws SQLException {
// TODO Auto-generated method stub
conn.setSchema(schema);
}
@Override
public String getSchema() throws SQLException {
// TODO Auto-generated method stub
return conn.getSchema();
}
@Override
public void abort(Executor executor) throws SQLException {
// TODO Auto-generated method stub
conn.abort(executor);
}
@Override
public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
// TODO Auto-generated method stub
conn.setNetworkTimeout(executor, milliseconds);
}
@Override
public int getNetworkTimeout() throws SQLException {
// TODO Auto-generated method stub
return conn.getNetworkTimeout();
}
}
裝飾類:MyConnectionWrapper 類
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
public class MyConnectionWrapper extends ConnectionWrapper{
private Connection conn;
private List<Connection> connList;
public MyConnectionWrapper(Connection conn,List<Connection> connList) {
super(conn);
this.conn = conn;
this.connList = connList;
}
@Override
public void close() throws SQLException {
connList.add(conn);
}
}
MyDatesource 類
package com.datasource.demo1;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import javax.sql.DataSource;
import com.jdbc.utils.JDBCUtils;
public class MyDataSource implements DataSource {
public List<Connection> connList = new ArrayList<Connection>();
//初始化提供連線
public MyDataSource(){
for (int i = 1; i <= 3; i++) {
connList.add(JDBCUtils.getConnection());
}
}
//從連線池獲得連線
@Override
public Connection getConnection() throws SQLException {
Connection conn = connList.remove(0);
MyConnectionWrapper connWraper = new MyConnectionWrapper(conn, connList);
return connWraper;
}
//下列程式碼不用管
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
// TODO Auto-generated method stub
return null;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
// TODO Auto-generated method stub
return false;
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public PrintWriter getLogWriter() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public int getLoginTimeout() throws SQLException {
// TODO Auto-generated method stub
return 0;
}
}
DataSourceDemo 類
package com.datasource.demo1;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.junit.Test;
import com.jdbc.utils.JDBCUtils;
public class DataSourceDemo {
@Test
public void demo1() {
Connection conn = null;
PreparedStatement pStatement = null;
ResultSet rs = null;
MyDataSource dataSource = null;
try {
dataSource = new MyDataSource();
conn = dataSource.getConnection();
String sql = "select * from account";
pStatement = conn.prepareStatement(sql);
rs = pStatement.executeQuery();
while (rs.next()) {
System.out.println(rs.getInt("id")+" "+rs.getString("name")+" "+rs.getDouble("money"));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtils.release(rs, pStatement, conn);//這個時候的conn傳入呼叫是歸還而不是銷燬。
}
}
}
開源連線池的使用
使用maven倉庫去下載且導包,本文暫不演示。
Druid
手動設定配置資訊方式:
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import org.junit.Test;
import com.alibaba.druid.pool.DruidDataSource;
import com.jdbc.utils.JDBCUtils;
public class DruidDemo1 {
@Test
public void name() {
Connection conn = null;
PreparedStatement pStatement = null;
ResultSet rs = null;
try {
DruidDataSource dataSource = new DruidDataSource();
/*---手動設定資料庫的資訊---*/
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///jdbc");
dataSource.setUsername("root");
dataSource.setPassword("");
conn = dataSource.getConnection();
String sql = "select * from account";
pStatement = conn.prepareStatement(sql);
rs = pStatement.executeQuery();
while (rs.next()) {
System.out.println(rs.getInt("id")+" "+rs.getString("name")+" "+rs.getDouble("money"));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtils.release(rs,pStatement ,conn);//自己的工具類,但是這些開源資料庫內部都是進行歸還而不是銷燬。
}
}
}
使用屬性檔案去配置資訊方式:
注意:屬性檔案中的key要求一致
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;
import javax.sql.DataSource;
import org.junit.Test;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.jdbc.utils.JDBCUtils;
public class DruidDemo1 {
@Test
public void name() {
Connection conn = null;
PreparedStatement pStatement = null;
ResultSet rs = null;
try {
Properties p = new Properties();
p.load(new FileInputStream("src/db.properties"));
DataSource dataSource = DruidDataSourceFactory.createDataSource(p);
conn = dataSource.getConnection();
String sql = "select * from account";
pStatement = conn.prepareStatement(sql);
rs = pStatement.executeQuery();
while (rs.next()) {
System.out.println(rs.getInt("id")+" "+rs.getString("name")+" "+rs.getDouble("money"));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtils.release(rs,pStatement ,conn);
}
}
}
C3P0
手動配置:
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import org.junit.Test;
import com.jdbc.utils.JDBCUtils;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class C3P0Demo1 {
@Test
public void demo1() {
Connection conn = null;
PreparedStatement pStatement = null;
ResultSet rs = null;
try {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
/*---手動設定資料庫的資訊---*/
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql:///jdbc");
dataSource.setUser("root");
dataSource.setPassword("");
conn = dataSource.getConnection();
String sql = "select * from account";
pStatement = conn.prepareStatement(sql);
rs = pStatement.executeQuery();
while (rs.next()) {
System.out.println(rs.getInt("id")+" "+rs.getString("name")+" "+rs.getDouble("money"));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtils.release(rs,pStatement ,conn);//自己的工具類,但是這些開源資料庫內部都是進行歸還而不是銷燬。
}
}
}
使用XML去配置資訊方式:
檔案資訊:
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql:///jdbc</property>
<property name="user">root</property>
<property name="password"></property>
<property name="initialPoolSize">5</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">20</property>
</default-config>
<!-- This app is massive! -->
<named-config name="oracle">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql::///jdbc</property>
<property name="user">root</property>
<property name="password"></property>
</named-config>
</c3p0-config>
測試方法
@Test
public void demo2() {
Connection conn = null;
PreparedStatement pStatement = null;
ResultSet rs = null;
try {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
//如果ComboPooledDataSource dataSource = new ComboPooledDataSource("oracle");
//則可以使用oracle的配置資訊,若引數錯誤則使用預設,不會報錯
/*建立連線池會自動去src下尋找c3p0-config檔案*/
conn = dataSource.getConnection();
String sql = "select * from account";
pStatement = conn.prepareStatement(sql);
rs = pStatement.executeQuery();
while (rs.next()) {
System.out.println(rs.getInt("id")+" "+rs.getString("name")+" "+rs.getDouble("money"));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtils.release(rs,pStatement ,conn);//自己的工具類,但是這些開源資料庫內部都是進行歸還而不是銷燬。
}
}
根據開源連線池,優化自己寫的工具類
以c3p0為例子:可以進行如下簡單改寫
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class JDBCUtils2 {
private static final ComboPooledDataSource dataSoure = new ComboPooledDataSource();
public static Connection getConnection() throws SQLException {
return dataSoure.getConnection();
}
//獲得連線池
public static DataSource getDataSource() {
return dataSoure;
}
public static void release(ResultSet rs,Statement statement,Connection conn) {
if (rs!=null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
if (statement!=null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
statement = null;
}
if (conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
public static void release(Statement statement,Connection conn) {
if (statement!=null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
statement = null;
}
if (conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
}
測試方法,如下:
@Test
public void demo3() {
Connection conn = null;
PreparedStatement pStatement = null;
ResultSet rs = null;
try {
conn = JDBCUtils2.getConnection();
String sql = "select * from account";
pStatement = conn.prepareStatement(sql);
rs = pStatement.executeQuery();
while (rs.next()) {
System.out.println(rs.getInt("id")+" "+rs.getString("name")+" "+rs.getDouble("money"));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtils2.release(rs,pStatement ,conn);//自己的工具類,但是這些開源資料庫內部都是進行歸還而不是銷燬。
}
}
四、Dbutils
是一個對JDBC進行簡單封裝的開源工具類庫,使用它能夠簡化JDBC應用程式的開發,同時也不會影響程式的效能。
在一般情況下如果執行CRUD的操作:
構造:
QueryRunner(Datasource ds) ;
方法:
int update(String sql , Object…args) ;
T query(string sql , ResultSetHandler rsh,Object…args);
如果有事務管理的話使用另一套完成CRUD的操作
因為需要獲取連線進行提交操作。
構造:
QueryRunner();
方法:
int update(Connection conn , string sql , Object…args) ;
T query(Connection conn, string sql , ResultSetHandler rsh,Object…args) ;
增刪改操作
增加:
import java.sql.SQLException;
import org.apache.commons.dbutils.QueryRunner;
import org.junit.Test;
import com.jdbc.utils.JDBCUtils2;
public class DBUtilsDemo1 {
@Test
public void demo1() throws SQLException {
QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
queryRunner.update("insert into account values(null,?,?)","ddd",10000);
}
}
執行後檢視sql如圖,插入成功:
修改: 原理如上只需修改即可。
queryRunner.update("update account set name=?,money=? where id=?","eee",20000,4);
刪除: 同上
queryRunner.update("delete from account where id = ?",4);
查詢操作
通常我們查詢之後目的不僅僅是列印到控制檯,而是把資料儲存在物件中或者是儲存到物件的集合中。
建立一個儲存的實體類: Account
public class Account {
private Integer id;
private String name;
private Double money;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
public String toString() {
return "Account [id=" + id + ", name=" + name + ", money=" + money + "]";
}
}
查詢一條記錄:
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.junit.Test;
import com.jdbc.utils.JDBCUtils2;
/*查詢*/
public class DBUtilsDemo2 {
@Test
public void demo() throws SQLException {
QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
Account account = queryRunner.query("select * from account where id = ?", new ResultSetHandler<Account>(){
@Override
public Account handle(ResultSet rs) throws SQLException {
Account account = new Account();
while (rs.next()) {
account.setId(rs.getInt("id"));
account.setName(rs.getString("name"));
account.setMoney(rs.getDouble("money"));
}
return account;
}
},1);
System.out.println(account);
}
}
查詢多條語句並且遍歷:
測試方法如下:
@Test
public void demo2() throws SQLException {
QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
List<Account> list= queryRunner.query("select * from account", new ResultSetHandler<List<Account>>(){
@Override
public List<Account> handle(ResultSet rs) throws SQLException {
List<Account> list = new ArrayList<Account>();
while (rs.next()) {
Account account = new Account();
account.setId(rs.getInt("id"));
account.setName(rs.getString("name"));
account.setMoney(rs.getDouble("money"));
list.add(account);
}
return list;
}
});
for(Account a : list) {
System.out.println(a);
}
}
執行如下圖:
ResultSetHandler的實現類
利用這個知識可以幫助我們快速完成資料的封裝。
1.ArrayHandler和ArrayListHandler
ArrayHandler : 將一條記錄封裝到一個陣列當中。這個陣列是object[]。
ArrayListHandler : 將多條記錄封裝到一個裝有object[]的List集合中,即list集合中存放object[]。
測試程式碼如下:
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.ArrayHandler;
import org.apache.commons.dbutils.handlers.ArrayListHandler;
import org.junit.Test;
import com.jdbc.utils.JDBCUtils2;
public class DButilsDemo3 {
@Test //查詢一條記錄
public void demo1() throws SQLException {
QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
Object[] objs = queryRunner.query("select * from account where id = ?", new ArrayHandler() ,1);
System.out.println(Arrays.toString(objs));
System.out.println("------------");
}
@Test //查詢多條記錄
public void demo2() throws SQLException {
QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
List<Object[]> list = queryRunner.query("select * from account", new ArrayListHandler());
for(Object[] obj : list) {
System.out.println(Arrays.toString(obj));
}
}
}
執行結果如下:
2.BeanHandler和BeanListHandler
BeanHandler : 將一條記錄封裝到一個JavaBean 中。
BeanListHandler : 將多條記錄封裝到一個裝有JavaBean的 List集合中。
下列僅給出測試方法程式碼:
@Test //查詢一條記錄
public void demo3() throws SQLException {
QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
Account account = queryRunner.query("select * from account where id = ?", new BeanHandler<Account>(Account.class),2);
System.out.println(account);
}
@Test //查詢多條記錄
public void demo4() throws SQLException {
QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
List<Account> list = (List<Account>) queryRunner.query("select * from account", new BeanListHandler<Account>(Account.class));
for(Account acc : list) {
System.out.println(acc);
}
}
3.MapHandler和MapListHandler
MapHandler : 將一條記錄封裝到一個Map集合中,Map的 key是列名,Map的value就是表中列的記錄值。
MapListHandler :將多條記錄封裝到一個裝有Map的List集合中。
@Test //查詢一條記錄
public void demo5() throws SQLException {
QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
Map<String, Object> map = queryRunner.query("select * from account where id = ?", new MapHandler(),2);
System.out.println(map);
}
@Test //查詢多條記錄
public void demo6() throws SQLException {
QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
List<Map<String, Object>> list = queryRunner.query("select * from account", new MapListHandler());
for(Map<String, Object> map : list) {
System.out.println(map);
}
}
4.ColumnListHandler、ScalarHandler、KeyedHandler
ColumnListHandler : 將資料中的某列封裝到List集合中
ScalarHandler : 將單個值封裝
KeyedHandler : 將一條記錄封裝到一個Map集合中。將多條記錄封裝到一個裝有Map集合的Map集合中。而且外面的Map的key是可以指定的
@Test //查詢某列記錄
public void demo7() throws SQLException {
QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
List<Object> list = queryRunner.query("select * from account", new ColumnListHandler<>("name"));
for(Object obj : list) {
System.out.println(obj);
}
}
@Test //查詢單值記錄
public void demo8() throws SQLException {
QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
Object obj = queryRunner.query("select count(*) from account", new ScalarHandler<>());
System.out.println(obj);
}
@Test //可以指定外面的key
public void demo9() throws SQLException {
QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
Map<Object, Map<String, Object>> map = queryRunner.query("select * from account", new KeyedHandler<>("name"));
for(Object o : map.keySet()) {
System.out.println(o + "->" + map.get(o)); // 根據鍵值獲取values,這裡的values是map集合
}
}
總結
如果你看到這裡,恭喜你,你會JDBC的基礎操作了,多去實戰吧!
相關文章
- 你不得不知道的MyBatis基礎知識之<resultMap>(4)MyBatis
- JDBC的基礎介紹JDBC
- Jdbc基礎五步JDBC
- JDBC基礎入門教程,輕鬆掌握jdbc基礎+核心技術,超全面!JDBC
- js基礎知識 你不知道的變數提升的坑JS變數
- JavaScript之你不知道的thisJavaScript
- 【0基礎學爬蟲】爬蟲基礎之資料儲存爬蟲
- 【0基礎學爬蟲】爬蟲基礎之檔案儲存爬蟲
- 【0基礎學爬蟲】爬蟲基礎之自動化工具 Pyppeteer 的使用爬蟲
- 【0基礎學爬蟲】爬蟲基礎之自動化工具 Playwright 的使用爬蟲
- 【0基礎學爬蟲】爬蟲基礎之自動化工具 Selenium 的使用爬蟲
- 【0基礎學爬蟲】爬蟲基礎之網路請求庫的使用爬蟲
- 小程式開發之基礎知識(0)
- Java程式設計基礎33——JDBCJava程式設計JDBC
- JDBC-MySql基礎操作詳解JDBCMySql
- Java String之你不知道的事Java
- 你不知道的javascript之繼承JavaScript繼承
- 0基礎如何學習Python?4種方法告訴你!Python
- Python4️⃣:0小白基礎之——流程控制專題Python
- Go語言 | goroutine不只有基礎的用法,還有這些你不知道的操作Go
- 0基礎學網路安全需要什麼基礎?
- 0基礎學GUI,先從基礎開始1GUI
- LEO原創-FMX之你不知道的ARC
- 關於mysql,需要掌握的基礎(二):JDBC和DAO層MySqlJDBC
- 0基礎Java自學之路Java
- 雲端計算基礎-0
- 北京0基礎學習Java培訓讓你不走彎路Java
- 0-目標檢測模型的基礎模型
- Linux和Windows的差異?0基礎需知!LinuxWindows
- 前端基礎之jQuery基礎前端jQuery
- 你所不知道的Java效能優化之String!Java優化
- EasyAndroid基礎整合元件庫之:EasyToast 簡化你的Toast操作Android元件AST
- 2023我還不知道的JSON Schema-基礎篇JSON
- 0基礎7日入門PythonPython
- python基礎筆記0_1Python筆記
- 0基礎學如何學web前端?Web前端
- Java 之 JDBCJavaJDBC
- Java之JDBCJavaJDBC