Util类
package tarena.util;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class DBUtil {
private static final String URL;
private static final String DRIVER;
private static final String USERNAME;
private static final String PASSWORD;
private static ThreadLocal threadLocal =
new ThreadLocal();
static {
try {
InputStream in = DBUtil.class.getResourceAsStream("/db.properties");
Properties props = new Properties();
props.load(in);
in.close();
URL=props.getProperty("url");
DRIVER=props.getProperty("driver");
USERNAME=props.getProperty("username");
PASSWORD=props.getProperty("password");
Class.forName(DRIVER); // 注册驱动
} catch(Exception e) {
System.out.println("无法获得数据库连接信息");
throw new RuntimeException(e);
}
}
private DBUtil() {}
public static Connection open() throws SQLException{
return DriverManager.getConnection(
URL,USERNAME,PASSWORD);
}
public static void close(
Connection con,
Statement stmt,
ResultSet rs) {
try {rs.close();} catch(Exception e) {}
try {stmt.close();} catch(Exception e) {}
try {con.close();} catch(Exception e) {}
}
public static Connection openInThread() throws SQLException{
Connection con =
(Connection)threadLocal.get();
if(null == con) {
con = open();
threadLocal.set(con);
}
return con;
}
public static void closeInThread() {
try {
Connection con = openInThread();
con.close();
threadLocal.remove();
} catch(Exception e) {}
}
}
测试类
package day02;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
import tarena.util.DBUtil;
public class JDBCTest3 {
public static void main(String[] args) throws Exception {
test1();
}
static void test1() throws Exception {
Connection con = null;
Statement stmt = null;
try {
con = DBUtil.openInThread();
con.setAutoCommit(false);
// 输入员工数据保存
// 如果姓名存在,删除再插入新数据
// 如果不存在,直接插入新数据
Emp emp = inputEmp();
if(nameExist(emp.getFirstName(), emp.getLastName())) {
deleteByName(emp.getFirstName(), emp.getLastName());
}
save(emp);
con.commit();
} catch(Exception e) {
con.rollback();
throw e;
} finally {
DBUtil.closeInThread();
}
}
private static void save(
Emp emp) throws Exception {
Connection con = DBUtil.openInThread();
PreparedStatement pstmt =
con.prepareStatement(
"insert into s_emp(id,first_name, last_name, salary) " +
"values(?,?,?,?)");
pstmt.setInt(1, emp.getId());
pstmt.setString(2, emp.getFirstName());
pstmt.setString(3, emp.getLastName());
pstmt.setDouble(4, emp.getSalary());
pstmt.executeUpdate();
}
private static void deleteByName(String firstName, String lastName) throws Exception {
Connection con = DBUtil.openInThread();
PreparedStatement pstmt =
con.prepareStatement(
"delete from s_emp " +
"where first_name=? " +
"and last_name=?");
pstmt.setString(1, firstName);
pstmt.setString(2,lastName);
pstmt.executeUpdate();
}
private static boolean nameExist(String firstName, String lastName) throws Exception {
Connection con = DBUtil.openInThread();
PreparedStatement pstmt =
con.prepareStatement(
"select * from s_emp " +
"where first_name=? " +
"and last_name=?");
pstmt.setString(1, firstName);
pstmt.setString(2,lastName);
ResultSet rs = pstmt.executeQuery();
// 指针下移有数据,即存在同名员工
boolean exist = rs.next();
rs.close();
pstmt.close();
return exist;
}
private static Emp inputEmp() {
Scanner sc = new Scanner(System.in);
System.out.print("请输入id:");
int id = sc.nextInt();
System.out.print("请输入first name:");
String fname = sc.next();
System.out.print("请输入last name:");
String lname = sc.next();
System.out.print("请输入salary:");
double sal = sc.nextDouble();
Emp e = new Emp(id,fname,lname,sal);
return e;
}
}
引用
元数据
数据连接元数据
DatabaseMetadata
数据库品牌、版本
表.....
结果集的元数据
ResultSetMetadata
列
getColumnCount() - 结果集中字段数量
getColumnName(序号) - 指定字段的名字
getColumnType(序号) - 指定字段的类型数字编号
使用Types中的常量做判断
getColumnTypeName(序号) - 指定字段的类型名称
java.sql.Types
封装表示字段类型的数字变号常量
Types.DATE - 年月日
Types.TIME - 时分秒
Types.TIMESTAMP - 年月日时分秒
ResultSet
数据传输量
setFetchSize(数据行数)
0 - JDBC驱动自行决定每次抓取的数据量
int age = rs.getInt("age");
// 刚取出的字段中数据在数据表中是否为null
boolean b = rs.wasNull();
double height = rs.getDouble("height");
b = rs.wasNull();
PreparedStatement
是Statement的子接口
比Statement更常用
1, 预编译的sql语句,重复执行相同的sql语句效率较高
pstmt = con.prepareStatement("select ...");
pstmt.executeQuery();
pstmt.executeQuery();
2, 对sql语句中参数数据进行设置
pstmt = con.prepareStatement(
"insert into emp(id,name,sal) values(?,?,?)");
pstmt.setInt(1,4534);
pstmt.setString(2, "1' or '1' = '1");
pstmt.setDouble(3,5000D);
pstmt.executeUpdate(); // 执行上面已经设置好的sql语句
pstmt.setInt(1, 4535);
pstmt.executeUpdate();
3, 不用拼sql,不用处理sql注入
事务处理
事务
1, 启动事务
无事务:自动提交 auto commit = true
启动事务:关闭自动提交 auto commit = false
con.setAtuoCommit(false);
到达事务上边界
2, 提交
con.commit();
到达事务下边界
3, 回滚
con.rollback();
1, 在捕获到异常时执行
2, 在一定条件下