JDBC
JDBC本质是一套接口(interface)
接口都有调用者和实现者,面向接口调用,面向接口实现类;
面向接口编程,本质面向抽象编程,解耦降低耦合度,实现高可扩展性。(多态);
java提供JDBC接口,数据库厂商根据接口进行实现(数据库厂家官网下载),提供jar包驱动(实现类),引用驱动进行数据库连接访问。
利用反射实现JDBC连接
public class javaPro{
ResourceBundle r = ResourceBundle.get ("popertites文件");
String value = r.getString(“key”);
Class c = Class.forName(value);
//通过反射,创建JDBC对象
JDBC jdbc = c.newInstance();
//实现连接
jdbc.getConnection();
}
JDBC编程6步
第一步:注册驱动(作用:告诉java程序,即将要连接的是那个品牌的数据库)
第二步:获取连接(表示JVM的进程和数据库进程之间的通道打开了,属于进程之间的通信,使用完之后一定要关闭)
第三步:获取数据库操作对象(专门执行SQL的对象)
第四步:执行SQL语句(DQL、DML)
第五步:处理查询结果(只有第四步执行的是SELECT语句的时候,才会有第五步的处理结果)
第六步:释放资源
public class JDBCTest01 {
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
//1.注册驱动
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
//2.建立连接
//统一资源定位符
//通信协议 jdbc:mysql:
//IP端口 localhost:3306
//资源名 sys-具体数据库实例名称
String url = "jdbc:mysql://localhost:3306/sys";
String user = "root";
String password = "123456";
conn = DriverManager.getConnection(url, user, password);
//测试验证数据库连接对象
//System.out.println(conn);
//3.获取数据库操作对象(执行SQL语句)
stmt = conn.createStatement();
//4.编写执行sql,jdbc语句不需要写分号
String sql = "select * from sys_user";
//执行dml语句,返回值是影响数据库条数
//in count = stmt.executeUpdate(sql);
//执行查询语句
stmt.executeQuery(sql);
rs = stmt.getResultSet();
//5.处理结果
while(rs.next()){
.....
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
//6.释放连接
//为了来保证资源一定是释放,在finally中关闭资源
//并且遵循从小到大依次关闭
//分别对其try...catch
try {
if (rs != null) {
rs.close();
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
try {
if (stmt != null) {
stmt.close();
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
try {
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
}
//类加载的方式注册驱动,可使用xxx.properties文件参数获取
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
statement存在SQL注入风险
使用preparedStatement,预编译数据库操作对象。解决用户提供的参数包含SQL关键字,但这些关键字为参与SQL编译,不会起作用。
sql语句中的变量使用 ? -占位符。
ps = conn.prepareStatement(sql);
//给占位符赋值参数,jdbc索引下表从1开始,几个占位赋值几个
ps.setString(1,参数)
ps.setString(2,参数)
//执行SQL
ps.executeQuery();
Statement与PreparedStatement比较
1、Statement会导致SQL注入不安全,PreparedStatement不会。
2、Statement编译一次执行一次,PreparedStatement执行效率库快,编译一次可以执行N次。
3、PreparedStatement在编译阶段会进行类型检查。preparedStatement.setXXX(1,参数)方法会对参数类型检查。
综上,大部分情况使用PreparedStatement
业务方面要求支持SQL注入、SQL语句拼接时才使用Statement。
JDBC中的默认事物是自动提交的,只要执行任意一条DML语句,就会提交;
但是实际开发过程中需要保持事物的一致性与原子性,需修改自动提交机制。
//开启手动提交事物
connections.setAutoCommit(false);
//事物提交
connections.commit();
//事物回滚
connections,rollback();
简化编程可以写JDBC工具类
import java.sql.*;
import java.util.ResourceBundle;
public class DBUtil {
/**
* 工具类中的构造方法建议私有
* 工具类的方法都是静态方法,不需要进行实例化,直接采用类名调用
*/
private DBUtil() {
}
;
//静态代码块,类加载时只执行一次。
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
/**
* 建立数据库链接
*
* @param porperties JDBC配置文件
* @return
* @throws SQLException
*/
public static Connection getConnection(String porperties) throws SQLException {
ResourceBundle resourceBundle = ResourceBundle.getBundle(porperties);
String url = resourceBundle.getString("url");
String username = resourceBundle.getString("username");
String password = resourceBundle.getString("password");
return DriverManager.getConnection("porperties", username, password);
}
/**
* 关闭资源
* 程序执行到这已经最后处理,上抛资源无人处理异常
*
* @param conn 连接对象
* @param ps 数据库操作对象
* @param rs 结果集
*/
public static void close(Connection conn, PreparedStatement ps, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
}
悲观锁和乐观锁
悲观锁:行级锁为悲观锁,事物必须排队,数据锁住了,不允许并发(select … for update)。
乐观锁:允许并发,事务不需要排队,提交事务前,根据版本号确认是否有事务进行更新,若当前获取的版本号不是最新的版本号则回滚事物,反之提交事物。
额外注释
ResourceBundle 用来读取poperties文件
popertites文件内容
key=value
ResourceBundle 使用方法
ResourceBundle r = ResourceBundle.get ("popertites文件名");
String value = r.getString(“key”);