目录
1、JDBC是什么
2、JDBC开发前的准备工作
3、JDBC编程六步
4.注意事项
5.DQL语句的悲观锁
1、JDBC是什么?
Java DataBase Connectivity(Java语言连接数据库)
JDBC是SUN公司制定的一套接口(interface),JDBC本质就是接口
java.sql.*; (这个软件包下有很多接口。)
?? ?????为什么SUN制定一套JDBC接口呢? ?? ??? ?因为每一个数据库的底层实现原理都不一样。 ?? ??? ?Oracle数据库有自己的原理。 ?? ??? ?MySQL数据库也有自己的原理。 ?? ??? ?MS SqlServer数据库也有自己的原理。 ?? ??? ?.... ?? ??? ?每一个数据库产品都有自己独特的实现原理。 ?? ?
2、JDBC开发前的准备工作
以idea为例,右击lib选择“Add as library”,加入mysql的jar包
?? ? 3、JDBC编程六步
第一步:注册驱动(作用:告诉Java程序,即将要连接的是哪个品牌的数据库)
第二步:获取连接(表示JVM的进程和数据库进程之间的通道打开了,这属于进程之间的通信,重量级的,使用完之后一定要关闭通道。)
第三步:获取数据库操作对象(专门执行sql语句的对象)
第四步:执行SQL语句(DQL DML....)
第五步:处理查询结果集(只有当第四步执行的是select语句的时候,才有这第五步处理查询结果集。)
第六步:释放资源(使用完资源之后一定要关闭资源。Java和数据库属于进程间的通信,开启之后一定要关闭。)
import java.sql.*;
public class JDBCTest03 {
public static void main(String[] args) {
Connection conn=null;
Statement stmt=null;
ResultSet rs=null;
try {
//1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接
conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/myemployees","root","111111");
//3.获取数据库操作对象
stmt= conn.createStatement();
//4.执行SQL语句
String sql="select email from employees where salary>12000";
rs=stmt.executeQuery(sql);
//5.处理查询结果集
while(rs.next()){
String email=rs.getString("email");
System.out.println(email);
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}finally {
//6.释放资源
if(rs!=null){
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(stmt!=null){
try {
(stmt).close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
}
4.注意事项
(1)Statement和PreparedStatement
- PreparedStatement常用于传值,Statement常用于字符串拼接
- Statement可能引发SQL注入,解决的办法是改用PreparedStatement
- PreparedStatement可以完成增删改,但日常更多用Statement
(2)使用资源绑定器,通过属性配置文件拿到信息
右击resources新建一个Resource Bunle
取名db.properties并写入以下内容:
##############mysql connectivity configuration###########
driver:com.mysql.cj.jdbc.Driver
url:jdbc:mysql://localhost:3306/myemployees
user:root
password:111111
更改代码:
//资源绑定器
ResourceBundle bundle=ResourceBundle.getBundle("resources/db");
//通过属性配置文件拿到信息
String driver=bundle.getString("driver");
String url=bundle.getString("url");
String user=bundle.getString("user");
String password=bundle.getString("password");
(3)关闭自动提交机制
JDBC默认自动支持自动提交:执行一条DML语句就自动提交一次 在实际开发中必须将JDBC的自动提交机制关闭,改成手动提交 当一个完整的事务结束后,再提交
- conn.setAutoCommit(false);关闭自动提交机制
- conn.commit();手动提交
- conn.rollback();手动回滚
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/*
模拟银行转账:1账户向2账户转账10000元
必须同时成功或同时失败
转账:执行两条update语句
JDBC默认自动支持自动提交:执行一条DML语句就自动提交一次
在实际开发中必须将JDBC的自动提交机制关闭,改成手动提交
当一个完整的事务结束后,再提交
conn.setAutoCommit(false);关闭自动提交机制
conn.commit();手动提交
conn.rollback();手动回滚
*/
public class JDBCTest10 {
public static void main(String[] args) {
Connection conn=null;
PreparedStatement ps=null;
try {
//1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接
//开启事务,关闭自动提交机制,改为手动提交
conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","111111");
conn.setAutoCommit(false);
//3.获取预编译的数据库操作对象
String sql="update banker set price=? where id=?";
ps=conn.prepareStatement(sql);
//给?传值
ps.setInt(1,15000);//第1个账户的存款
ps.setInt(2,1);//第1个账户
int count=ps.executeUpdate();
ps.setInt(1,5000);//第2个账户的存款
ps.setInt(2,2);//第2个账户
count+=ps.executeUpdate();
System.out.println(count==2 ? "转账成功":"转账失败");
//手动提交,事务结束,每一次都要手动关!!!
conn.commit();
} catch (Exception e) {
//保险起见,出现空指针异常则回滚!!!
try {
if(conn!=null){
conn.rollback();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
e.printStackTrace();
}finally {
//6.释放资源
if(ps!=null) {
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
(4)为了便于开发,封装一个JDBC的工具类DBUtil
import java.sql.*;
import java.util.ResourceBundle;
public class DBUtil {
//工具类中的构造方法一般都是私有的,是为了防止new对象
//工具类中的方法都是静态的,不需要new对象,直接使用“类名.”的方式调用
private DBUtil(){
}
//类加载时绑定属性资源文件
private static ResourceBundle bundle=ResourceBundle.getBundle("resources/db");
//注册驱动
static{
try {
Class.forName(bundle.getString("driver"));
} catch (Exception e) {
e.printStackTrace();
}
}
//获取数据库连接对象,返回一个新的连接对象
public static Connection getConnection() throws SQLException {
String url=bundle.getString("url");
String user=bundle.getString("user");
String password=bundle.getString("password");
Connection conn= DriverManager.getConnection(url,user,password);
return conn;
}
//关闭资源,分别关闭连接对象,数据库操作对象,查询结果集
//用Statement将来也可以传它的子类过来
public static void close(Connection conn, Statement stmt, ResultSet rs){
if(rs!=null){
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(stmt!=null){
try {
(stmt).close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
测试DUBil工具类
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class JDBCTest11 {
public static void main(String[] args) {
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
try {
//获取连接
conn=DBUtil.getConnection();
//获取预编译的数据库操作对象
String sql="select email,salary from employees where email like ?";
ps=conn.prepareStatement(sql);
//给?传值
ps.setString(1,"A%");
//执行sql语句
rs=ps.executeQuery();
//处理结果集
while(rs.next()){
System.out.println(rs.getString("email")+","+rs.getInt("salary"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
//释放资源
DBUtil.close(conn,ps,rs);
//如果没有结果集,关闭的时候第三个参数传null
}
}
}
5.DQL语句的悲观锁
对DQL语句来说,末尾可以添加关键字:for update
select ename,sal from emp where job = 'MANAGER' for updata;
以上SQL语句的含义是: ?? ?在本次事务的执行过程中,job='MANAGER'的记录被查询 ?? ?这些记录在我执行的过程中,任何人和任何事务都不能对这些记录进行修改,直到当前事务结束 ?? ?这种机制是:行级锁机制(悲观锁)
使用行级锁机制在当前事务中对job_id='ST_MAN'的记录进行查询并锁定
String sql="select first_name,salary from employees where job_id=? for update";
ps=conn.prepareStatement(sql);
ps.setString(1,"ST_MAN");
rs=ps.executeQuery();
|