JDBC
結(jié)果集元數(shù)據(jù)
ResultSetMetaData用于描述查詢(xún)結(jié)果的相關(guān)信息,其中包含列名稱(chēng)榆纽,列數(shù)量夺英,類(lèi)數(shù)據(jù)類(lèi)型等.
原理:
1.png
使用案例:
public static void main(String[] args) {
Connection conn = null;
try {
conn = DBUtils.getConnection();
String sql = "select * from robin_user";
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(sql);
//結(jié)果集元數(shù)據(jù)
ResultSetMetaData meta = rs.getMetaData();
int n = meta.getColumnCount();
for (int i = 1; i <=n ; i++) {
// i = 1 ... n
String name = meta.getColumnName(i);
System.out.println(name);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
DBUtils.close(conn);
}
}
作業(yè):
/**
* 打印一個(gè)SQL查詢(xún)結(jié)果的全部列名
* @param sql
*/
public static void print(String sql) {
//...
}
JDBC 實(shí)務(wù)控制
數(shù)據(jù)庫(kù)提供了實(shí)務(wù)控制功能皿伺,支持ACID特性.
JDBC提供了API,方便的調(diào)用數(shù)據(jù)庫(kù)的實(shí)務(wù)功能缭召,其方法有:
相關(guān)API:
- Connection.getAutoCommit():獲得當(dāng)前事務(wù)的提交方式变泄,默認(rèn)為true
- Connection.setAutoCommit():設(shè)置事務(wù)的的提交屬性令哟,參數(shù)是
- true:自動(dòng)提交;
- false:不自動(dòng)提交;
- Connection.commit():提交事務(wù)
- Connection.rollback():回滾事務(wù)
API調(diào)用模板:
Connection conn = null;
try {
conn = DBUtils.getConnection();
//取消自動(dòng)提交,后續(xù)手動(dòng)提交
conn.setAutoCommit(false);
//SQL... update
//SQL... update
// 余額不足 拋出異常 throw e;
//SQL... update
conn.commit();
} catch (Exception e) {
e.printStackTrace();
DBUtils.rollback(conn);
} finally {
DBUtils.close(conn);
}
提示:事務(wù)API經(jīng)典的用法是采用如下模板妨蛹,其中DBUtils.rollback()方法封裝了回滾方法,其聲明如下:
public static void close(Connection conn) {
if(conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
事務(wù)測(cè)試案例數(shù)據(jù):
create table account(
id int(6),
name varchar(100),
balance float(8,2)
);
insert into account (id,name,balance) values (1,'范老師',500);
insert into account (id,name,balance) values (2,'劉老師',1500);
insert into account (id,name,balance) values (3,'河仙姑',2000);
update account set balance=balance-1000 where id=2;
update account set balance=balance+1000 where id=1;
commit;
rollback;
案例:
public class Demo03 {
public static void main(String[] args) {
pay(3,4,200);
System.out.println("ok");
}
public static void pay(int from,int to,double money) {
String sql1 = "update account set balance=balance+? where id=?";
String sql2 = "select balance from account where id=?";
Connection conn = null;
try {
conn = DBUtils.getConnection();
conn.setAutoCommit(false);
PreparedStatement ps = conn.prepareStatement(sql1);
//減錢(qián)
ps.setDouble(1, -money);
ps.setInt(2, from);
int n = ps.executeUpdate();
if(n!=1) {
throw new Exception("扣錯(cuò)了");
}
//增加
ps.setDouble(1, money);
ps.setInt(2, to);
n = ps.executeUpdate();
if(n!=1) {
throw new Exception("加錯(cuò)了");
}
ps.close();
//檢查
ps = conn.prepareStatement(sql2);
ps.setInt(1, from);
ResultSet rs = ps.executeQuery();
while(rs.next()) {
double bal = rs.getDouble(1);
if(bal<0) {
throw new Exception("透支");
}
}
conn.commit();
} catch (Exception e) {
e.printStackTrace();
DBUtils.rollback(conn);
} finally {
DBUtils.close(conn);
}
}
}
批量更新
批量更新的優(yōu)勢(shì)
- 批處理:發(fā)送到數(shù)據(jù)庫(kù)作為一個(gè)單元執(zhí)行的一組更新語(yǔ)句
- 批處理降低了應(yīng)用程序與數(shù)據(jù)庫(kù)之間的網(wǎng)絡(luò)調(diào)用
- 相比單個(gè)SQL語(yǔ)句的處理晴竞,批處理更為有效
2.png
用法:
-
addBatch(String sql)
- Statement類(lèi)的方法蛙卤,可以將多條sql語(yǔ)句添加Statement對(duì)象的SQL語(yǔ)句列表中
-
addBatch()
- PreparedStatement類(lèi)的方法,可以將多條預(yù)編譯的sql語(yǔ)句添加到PreparedStatement對(duì)象的SQL語(yǔ)句列表中
-
executeBatch()
- 把Statemennt對(duì)象或PreparedStatemenn對(duì)象語(yǔ)句列表中的所有SQL語(yǔ)句發(fā)送給數(shù)據(jù)庫(kù)進(jìn)行處理
-
clearBatch()
- 清空當(dāng)前SQL語(yǔ)句列表
批量執(zhí)行DDL
public class Demo04 {
public static void main(String[] args) {
String sql1 = "create table log_01(id int(8),msg varchar(100))";
String sql2 = "create table log_02(id int(8),msg varchar(100))";
String sql3 = "create table log_03(id int(8),msg varchar(100))";
// 執(zhí)行一批SQL
Connection conn = null;
try {
conn = DBUtils.getConnection();
Statement st = conn.createStatement();
// sql1 添加到Statement的緩存中
st.addBatch(sql1);
st.addBatch(sql2);
st.addBatch(sql3);
// 執(zhí)行一批SQL
int[] ary = st.executeBatch();
System.out.println(Arrays.toString(ary));
System.out.println("OK");
} catch (Exception e) {
e.printStackTrace();
} finally {
DBUtils.close(conn);
}
}
}
批量插入數(shù)據(jù)
public class Demo05 {
public static void main(String[] args) {
String sql = "insert into robin_user (id,name,pwd) values (?,?,?)";
Connection conn = null;
try {
conn = DBUtils.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
for (int i = 0; i < 100; i++) {
//替換參數(shù)
ps.setInt(1, i);
ps.setString(2, "name"+i);
ps.setString(3, "123");
//將參數(shù)添加到ps緩沖區(qū)
ps.addBatch();
}
//批量執(zhí)行
int[] ary = ps.executeBatch();
System.out.println(Arrays.toString(ary));
} catch (Exception e) {
e.printStackTrace();
} finally {
DBUtils.close(conn);
}
}
}
防止OutOfMemory
- 如果Preparedstatement對(duì)象中的緩存列表包含過(guò)多的待處理數(shù)據(jù)噩死,可能會(huì)產(chǎn)生OutOfMerry錯(cuò)誤
返回自動(dòng)主鍵
JDBC API 提供了返回插入數(shù)據(jù)期間生成的ID的API,
API方法:
- PrepareStatement ps = con.prepareStatement(sql,列名列表);
- rs = stmt.getGeneratement();
3.png
create table r_post(
id int(8) auto_increment primary key ,
content varchar(100),
k_id int(8)
);
create table r_keywords(
id int(8) auto_increment primary key,
word varchar(8)
);
需要執(zhí)行的SQL:
insert into r_keywords (id,word) values (null,?);
insert into r_post (id,content,k_id) values (null,?,?)
案例:
public class Demo06 {
public static void main(String[] args) {
Connection conn = null;
try {
conn = DBUtils.getConnection();
conn.setAutoCommit(false);
String sql = "insert into r_keywords (id,word) values (null,?)";
String[] cols = {"id"};
//自動(dòng)生成序號(hào)的列名
PreparedStatement ps = conn.prepareStatement(sql,cols);
ps.setString(1, "霧霾");
int n = ps.executeUpdate();
if(n!=1) {
throw new Exception("話題添加失敗");
}
//獲取自動(dòng)生成的ID
ResultSet rs = ps.getGeneratedKeys();
int id = -1;
while(rs.next()) {
id = rs.getInt(1);
}
rs.close();
ps.close();
sql = "insert into r_post (id,content,k_id) values (null,?,?)";
ps=conn.prepareStatement(sql);
ps.setString(1, "今天天氣不錯(cuò)颤难,晚上有霧霾");
ps.setInt(2, id);
n = ps.executeUpdate();
if(n!=1) {
throw new Exception("天氣太糟");
}
conn.commit();
System.out.println("OK");
} catch (Exception e) {
e.printStackTrace();
DBUtils.rollback(conn);
} finally {
DBUtils.close(conn);
}
}
}
作業(yè)
- 設(shè)計(jì)一個(gè)方法打印一個(gè)SQL查詢(xún)結(jié)果的全部列名
- 利用JDBC事物保護(hù)一個(gè)匯款業(yè)務(wù)的完整性
- 批量建立10個(gè)表,再批量的向每個(gè)插入100條數(shù)據(jù)
- 向部門(mén)表插入一個(gè)數(shù)據(jù)并且返回自動(dòng)生成的ID