JDBC回顾+总结
JDBC概念
JDBC(Java DataBase Conntivtiy),翻译成中文就是java链接数据库。JDBC本质是由sun公司提供的一些接口,然后由数据库厂家来实现这些接口,由程序员来调用这些接口。
JDBC简单使用总结
JDBC对于使用有着恒古不变的六步
加载数据库驱动;对于加载数据库驱动有着两种方法:
- 利用反射来加载驱动中的类。
- 调用java.sql包中的DriverManager.deregisterDriver(Driver driver)方法来实现驱动加载。两者一般都用第一种。
- 链接数据库。
- 获取数据库操作对象
- 执行sql语句
- 查询结果集
- 关闭数据源
代码演示:
import java.sql.*;
public class JDBCtest01 {
public static void main(String[] args) {
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
//1.注册驱动
// DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Class.forName("com.mysql.jdbc.Driver");
//2.链接数据库
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test03","root","1234");
//编写sql语句 “?”占位符
String sql = "select * from emp where empno= ?";
//3.获取数据库操作对象,预编译sql语句
ps = con.prepareStatement(sql);
//给占位符传值
ps.setString(1,"7369");
//4. 执行sql语句
rs =ps.executeQuery();
//5.查询结果集
while(rs.next()){
System.out.println(rs.getString("empno") +" "+
rs.getDouble("sal") + " "+
rs.getString("ename") +" "+
rs.getInt("deptno")
);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}catch (SQLException e){
e.printStackTrace();
}finally {
//6. 关闭数据源
if(rs!=null){
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(ps!=null){
try {
ps.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(con!=null){
try {
con.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
}
执行结果:
7369 800.0 张翠山 20
Process finished with exit code 0
properties配置文件联合与JDBC技术联合应用
在简单的JDBC实现编程六步中,对于加载驱动、填写url地址、账户名、账户密码这些都可以写一个配置文件来保存,这样可以保证代码的灵活性,在改动数据或者账户名密码的时候只需要修改配置文件里面的参数就可。
代码演示
配置文件:
driver = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/test03
user = root
password = 1234
测试类代码:
import java.sql.*;
import java.util.ResourceBundle;
public class JDBCtest02 {
public static void main(String[] args) {
ResourceBundle rb = ResourceBundle.getBundle("jdbc");
String driver = rb.getString("driver");
String url = rb.getString("url");
String user = rb.getString("user");
String password = rb.getString("password");
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
//1.注册驱动
Class.forName(driver);
//2.链接数据库
con = DriverManager.getConnection(url,user,password);
//编写sql语句 “?”占位符
String sql = "select * from emp where empno= ?";
//3.获取数据库操作对象,预编译sql语句
ps = con.prepareStatement(sql);
//给占位符传值
ps.setString(1,"7369");
//4. 执行sql语句
rs =ps.executeQuery();
//5.查询结果集
while(rs.next()){
System.out.println(rs.getString("empno") +" "+
rs.getDouble("sal") + " "+
rs.getString("ename") +" "+
rs.getInt("deptno")
);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}catch (SQLException e){
e.printStackTrace();
}finally {
//6. 关闭数据源
if(rs!=null){
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(ps!=null){
try {
ps.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(con!=null){
try {
con.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
}
创建简单好用的JDBC工具类
对于繁琐的JDBC六步编程来说,总不能每一次都写六步代码来连接数据库,虽然有了配置文件的使用,每次改变一下参数就可以了,但是如果有其他的业务需求的话,就比较麻烦了。java是一门面向对象编程语言,所以我们编写一些工具类来对JDBC更简单的使用。
代码演示
初始化配置文件
package com.java.utils;
import java.util.ResourceBundle;
public class ConnectionManager {
private static ResourceBundle rb;
static {
rb = ResourceBundle.getBundle("jdbc");
}
public static String getString(String key){
return rb.getString(ky);
}
}
加载驱动、链接数据库、关闭操作源
package com.java.utils;
import java.sql.*;
public class JDutil {
private static Connection con;
private static PreparedStatement ps;
private static ResultSet rs;
private static String driver = ConnectionManager.getString("driver");
private static String user = ConnectionManager.getString("user");
private static String url = ConnectionManager.getString("url");
private static String password = ConnectionManager.getString("password");
static {
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,user,password);
}
public static void close(Connection con,PreparedStatement ps,ResultSet rs){
if(rs!=null){
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(ps!=null){
try {
ps.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(con!=null){
try {
con.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
编写工具类
package com.java.dao;
import com.java.utils.JDutil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class BaseDao {
private static Connection con;
private static PreparedStatement ps;
/**
- 查询语句方法
- @param sql sql语句
- @param psim 可变参数
- @return
*/
public static ResultSet executeQuery(String sql, Object...psim){
ResultSet rs = null;
try {
con = JDutil.getConnection();
ps = con.prepareStatement(sql);
for (int i = 0; i
}
rs = ps.executeQuery();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JDutil.close(null,null,null);
}
return rs;
}
/**
- 修改方法
- @param sql sql语句
- @param psim 可变参数
- @return 执行的条数
*/
public static int executeUpdate(String sql,Object...psim){
int rows = 0;
try {
con = JDutil.getConnection();
ps = con.prepareStatement(sql);
for (int i = 0; i < psim.length; i++) {
ps.setObject(i+1,psim[i]);
}
rows = ps.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JDutil.close(con,ps,null
);
}
return rows;
}
}
编写测试类
package com.java.test;
import com.java.dao.BaseDao;
import com.java.utils.JDutil;
import java.sql.ResultSet;
import java.sql.SQLException;
public class JDBCtest03 {
public static void main(String[] args) {
ResultSet resultSet = null;
try {
/*
- sql查询语句测试
- */
String sql = "select * from emp where empno = ?";
resultSet = BaseDao.executeQuery(sql, 7369);
System.out.println(resultSet.next() ? resultSet.getString("ename") : "sql语句执行失败");
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JDutil.close(null,null,resultSet);
}
//修改测试
String sql = "update emp set ename = ? where empno = ?";
int rows = BaseDao.executeUpdate(sql, "张三", 7369);
System.out.println(rows > 0 ?"修改成功" : "修改失败");
}
}
运行结果
张翠山
修改成功
Process finished with exit code 0
自动提交与事务提交
JDBC有一个机制,在一个事务中执行sql语句的时候,你编译了几条sql语句就会自动执行,在某些场景,当你执行完第一条sql语句的时候,程序就出错了,这个时候后台是没有结果的,但是莫名其妙的就执行了一条语句,加入这是个删除语句。在你没有备份的时候,就会丢失数据。但是java提供了一些方法来讲一个事务改为事务提交(手动提交)。
setAutoCommit(false);事务开始,此方法可以将事务自动提交改为手动提交
public static void main(String[] args) {
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.链接数据库
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test03","root","1234");
// 将自动提交改为手动提交
con.setAutoCommit(false);
commit();事务结束
//编写sql语句 “?”占位符
String sql = "select * from emp where empno= ?";
//3.获取数据库操作对象,预编译sql语句
ps = con.prepareStatement(sql);
//给占位符传值
ps.setString(1,"7369");
//4. 执行sql语句
rs =ps.executeQuery();
//5.查询结果集
while(rs.next()){
System.out.println(rs.getString("empno") +" "+
rs.getDouble("sal") + " "+
rs.getString("ename") +" "+
rs.getInt("deptno")
);
}
// 事务结束
con.commit();
rookback();遇到异常,事务回滚
}catch (SQLException e){
try {
//事务回滚
con.rollback();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
e.printStackTrace();
}
statment与Preparedstatment的区别
Java中JDBC有很多中方法可以进行查询,但是最常用的就是Connection中的preparestatment和statment了,这两种方式打开数组的游标进行查询。两者的区别:
- 安全性
这条sql语句是模仿了sql注入的语句
String sql = "select * from login username = '"+username+"',password = '"+password+"'";
当用户输入:
username: fisa
password: fisa' or '1' = '1这样就会显示信息正确,因为sql语句是再用户输入完之后运行的,所以在输入这些信息的时候,sql语句变成了or ‘1’=‘1’,sql语句恒成立,所以说statment在某些条件下是不安全的。 但preparestatment这样写就会报错,这也是两条语句的执行顺序有关。
- 语句执行方式
statment
Statment st = con.createstatment();
String sql = "select * from login username = '"+username+"',password = '"+password+"'";
ResultSet rs = st.executeQuery(sql)prepareStatment
String sql = "select * from login username = ? ,password = ?";
PreparedStatment ps = con.prepareStatement(sql);
ps.setString(1,username);
ps.setString(2,password);
ResultSet rs = st.executeQuery()
statment是直接对sql语句进行编译,而prepareStatment则是先对sql语句进行预编译,然后再通过占位符进行传值:
- 小总结:在安全性和代码执行顺序上以及底层实现原理上,statment和prepareStatment两者的差别是惊人的,也可以看出prepareStatment的执行效率更高。
悲观锁与乐观锁
JDBC悲观锁与乐观锁,首先悲观锁和乐观锁是多线程里面的,在JDBC里面涉及到了悲观锁这一项。
悲观锁: 悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。
乐观锁:乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。
JDBC悲观锁(也叫行级锁)
String sql = "select * from emp where ename = 'King' for update"
就是在查询语句后面加一个for update,这样这一条查询的语句就会被锁住,当你执行另一个程序想要将这条语句查询的信息去进行修改或者删除的时候就执行不了,所以被称为悲观锁。