JDBC
Java Database Connectivity
Java数据库连接技术,由一组java语言编写的类与接口组成,可以为多种关系型数据库提供统一访问。
作用:可以使用java语言操作数据库
JDBC中重要API
class | java.sql.DriverManager |
interface | java.sql.Connection |
interface | java.sql.Statement |
interface | java.sql.ResultSet |
JDBC开发步骤(重要)
public static void main(String[] args) {
// 1、加载数据库驱动
// 2、获取数据库连接
// 3、准备SQL语句,通过preparedStatement发送SQL语句
// 4、使用resultSet,接收返回来的结果集
// 5、关闭资源(先开后关原则)
ResultSet rs = null;
Connection conn = null;
PreparedStatement ps = null;
try {
Class.forName("oracle.jdbc.OracleDriver");
conn = DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:xe", "hr", "hr");
String sql = "select * from employees where rownum<=10";
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
while (rs.next()) {
System.out.println(rs.getString(1) + "\t" + rs.getString(2)
+ "\t" + rs.getString(3));
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (rs != null) {
rs.close();
}
if (ps != null) {
ps.close();
}
if (conn != null) {
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
补充
Statement:
Statement st = conn.createStatement();
int st.executeUpdate(sql); //执行增删改操作(有参)
ResultSet st.executeQuery(sql); //执行查询操作(有参)作为ResultSet的引入
//缺点:存在SQL注入的风险
PreparedStatement【重点】://继承Statement
- 编写参数化SQL:
String sql = "select * from account where cardId = ? and password = ?" ;
- 绑定动态参数:
ps.setInt(1,值);//参数位置从1开始
ps.setDouble(2,值);
ps.setString(3,值);
ps.setDate(4,值);
ps.setObject(5,值);
- 发送绑定参数后的SQL语句到Oracle数据库中:
int ps.executeUpdate(); //执行增删改操作(无参)
ResultSet ps.executeQuery(); //执行查询操作(无参) 作为ResultSet的引入
作用:发送预处理的SQL语句。
优势:防止SQL注入攻击,执行多个同构SQL的效率高。
预编译:
1). 验证用户访问权限。
2). 验证语法是否正确。
3). 计算访问计划(Access Plan)等效与Oracle的Map集合,将SQL语句一起缓存到内存中。首次比较耗时SQL=key/Plan = value
4). 通过SQL语句查找Oracle缓存的访问计划并执行。
扫描二维码关注公众号,回复:
3051557 查看本文章
JDBC进一步封装*(properties文件)
通过字节流读取配置文件jdbc.properties中的连接信息
public class JDBCUtil {
private static final Properties prop = new Properties();
static{
try {
InputStream is = new FileInputStream("bin\\jdbc.properties");
prop.load(is);
String driver = prop.getProperty("driver");
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection(){
String url=prop.getProperty("url");
String username=prop.getProperty("username");
String password=prop.getProperty("password");
try {
return DriverManager.getConnection(url,username,password);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public static void release(Connection conn,PreparedStatement ps,ResultSet rs){
try {
if(rs!=null){
rs.close();
}
if(ps!=null){
ps.close();
}
if(conn!=null){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
jdbc.properties
driver=oracle.jdbc.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:xe
username=jsk
password=jsk
JDBC封装(最终版)
事务控制
1、事务的边界:业务方法的首行–>整个方法结束(全部视为原子操作,要成功、都成功;要失败、都失败。)
2、手动控制事务:
I. 修改事务提交方案:conn.setAutoCommit(false);
II. conn.commit();
III. conn.rollback();
IV. trycatch final:异常的向上报告,连接对象的释放。
保证service(业务逻辑层与数据访问层使用同一个数据库的连接Connection):
通过ThreadLocal工具实现Connection与线程的绑定,通过JDBCUtil.getConnection()时,先判断线程中是否绑定了Connection,如果已经绑定则拿出此Connection使用;如果没有则重新获取新的Connection对象,并绑定到线程中。
注意:最后关闭Connection资源时,需要把线程中的Connection也移除
tl.remove();
代码示例
public class JDBCUtil {
private static final Properties prop = new Properties();
private static final ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
static{
try {
InputStream is = new FileInputStream("bin\\jdbc.properties");
prop.load(is);
String driver = prop.getProperty("driver");
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection(){
Connection conn = tl.get();
if(conn==null){
String url = prop.getProperty("url");
String username = prop.getProperty("username");
String password = prop.getProperty("password");
try {
conn = DriverManager.getConnection(url,username,password);
tl.set(conn);
return conn;
} catch (SQLException e) {
e.printStackTrace();
}
}
return conn;
}
public static void release(Connection conn,PreparedStatement ps,ResultSet rs){
try {
if(rs!=null){
rs.close();
}
if(ps!=null){
ps.close();
}
if(conn!=null){
conn.close();
tl.remove();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
总结
I. 线程工具类:可以在整个线程(单条执行路径)所持有的Map中,存储一个键(threadlocal)值(conn)。
II. 将参数对象(Connection conn)添加到当前线程中:
private static finalThreadLocal<Connection> tl = new ThreadLocal<Connection>(); //工具类
III. 修改getConnection方法:
Connection conn = tl.get(); //获取线程中保存的Connection对象
if(conn == null){ //当线程中没有保存过Connection对象时
conn =DriverManager.getConnection(url, userName, password); //获取连接对象
tl.set(conn); //并保存至线程中
}
return conn;
IV. 在release中关闭conn时,同时tl.remove(); //移除线程中的连接对象,只有业务提交或回滚之后才关闭、移除连接。