目录
1、JDBC是什么?
为什么SUN制定一套JDBC接口呢?
因为每一个数据库的底层实现原理都不一样。
Oracle数据库有自己的原理。
MySQL数据库也有自己的原理。
MS SqlServer数据库也有自己的原理。
....
每一个数据库产品都有自己独特的实现原理。
2、JDBC开发前的准备工作
以idea为例,右击lib选择“Add as library”,加入mysql的jar包
3、JDBC编程六步
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.注意事项
- PreparedStatement常用于传值,Statement常用于字符串拼接
- Statement可能引发SQL注入,解决的办法是改用PreparedStatement
- PreparedStatement可以完成增删改,但日常更多用Statement
右击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");
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();
}
}
}
}
}
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语句的悲观锁
select ename,sal from emp where job = 'MANAGER' for updata;
以上SQL语句的含义是:
在本次事务的执行过程中,job='MANAGER'的记录被查询
这些记录在我执行的过程中,任何人和任何事务都不能对这些记录进行修改,直到当前事务结束
这种机制是:行级锁机制(悲观锁)
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();