老狗——Java JDBC(Java Database Connectivity)
先写好注释,把逻辑通一通,然后填代码。
1 JDBC 概念和使用
1.1 Java 的数据获取方式:
- 直接声明变量并赋值
- Scanner类控制台输入
- IO流(将营盘村初中的数据读取到Java中)
- socket +io
- 从数据库中获取
1.2 JDBC概念
- 问题:Java和数据库之间的沟通不一致
- 解决:数据库厂商对外提供Java支持的接口
- 使用:创建类实现接口(操作数据库);数据库厂商对外提供了数据库操作的驱动包(翻译官角色);
- 结论:JDBC其实就是数据库厂商对外提供的能够对自己的数据库进行操作的驱动包,即Jar文件
1.3 JDBC的使用
CURD + 事务 + MVC思想
JDBC的基本使用流程:
- 导入jar包
- 声明JDBC变量
- 声明JDBC参数
- 加载驱动
- 创建数据库连接
- 获取数据库连接对象
- 创建sql命令对象
- 执行sql命令
- 关闭资源
2 JDBC - CURD
/* JDBC - CURD */
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class TestJDBC {
public static void main(String[] args){
// 声明JDBC变量,防止try catch finally 拿不到
Connection conn = null;
Statement statement = null;
// 声明JDBC参数
String driver = "oracle.jdbc.driver.OracleDriver";
String url = "jdbc:oracle:thin:@host:port:SID ";
String username = "zhy";
String password = "pwd";
try {
// 1 加载驱动类
Class.forName(driver); //ojdbc6.jar使用此包该句可省略不写
// 2 获取数据库连接对象(连接指定的数据库)
conn = DriverManager.getConnection(url, username, password);
// 3 获取sql命令对象(编译和发送sql命令给数据库)
statement = conn.createStatement();
// 4 创建sql命令
// 添加
String sql = "insert into xxx values(xxxx)";
// 修改
String sname = "xxx"
String sql = "update collectionname set sname='"+sname+"' where xxx='xx'";
// 删除
String sql = "delete from xxx where xxx='xx'";
// 注:更新和删除找不到数据,不会报错
// 更新
String sql = "select * from student";
// 5 执行sql命令
// 增加、修改、删除
int i = statement.executeUpdate(sql); // i >0表示sql执行成功修改的数据量,<0表示未执行成功
System.out.println("执行结果: " + i);
// 查询
ResultSet rs = statement.executeQuery(sql);
while (rs.next()){
//创建查询数据的对象
Student stu = new Student();
stu.setSnum(rs.getInt("sum"));
stu.setSname(rs.getString("sname"));
// ...
// 将对象存储到 ArrayList 中
list.add(stu);
}
创建DaoImpl层对象
// StudentDaoImpl sd = new StudentDaoImpl();
// ArrayList<student> ls = sd.getStudentInfo();
// 问题:查询返回值的类型是ResultSet,是基于指针进行数据存储的,不便于数据的针对性获取
// 解决:将数据转换到ArrayList中进行存储
// 使用:创建和表结构相同的实体类进行单条数据的存储(一条数据就是一个实例化对象),将对象存储到ArrayList中
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
// 6 关闭资源
// cancel()是在数据库连接的时候取消连接操作
// close()是在连接完成后,关闭这个连接
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
/*
常见的JDBC错误:
1、CassNotFoundException 驱动类未找到
2、java.sql.SQLException URL\用户名\密码 错误
3、java.sql.SQLSyntaxException sql语句错误
4、java.sql.SQLIntegrityConstrainViolationException 主键冲突
*/
}
}
3 JDBC 事务管理
事务:一个事件的完成需要几个字操作的联合完成,只要有一个子操作执行失败,则数据回滚到原始状态,都成功则提交数据。
/* JDBC - Transaction */
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/*
JDBC - Transaction
转账业务
示例:张三给李四转账100元。
注意:JDBC中的事务是自动提交的。
问题:如果在业务的处理过程中,某条sql语句执行失败,但是数据已经被更改了。
解决:设置JDBC的事务为手动提交,sql语句都执行成功后再同意提交,只要有失败的就回滚。
使用:conn.setAutoCommit(false); 并使用 try catch 进行 sql 命令执行的异常处理。
try 中 conn.commit(), catch 中 conn.rollback()
*/
public class TestTransaction {
public static void main(String[] args) {
// 声明JDBC变量,防止try catch finally 拿不到
Connection conn = null;
Statement statement = null;
// 声明JDBC参数
String driver = "oracle.jdbc.driver.OracleDriver";
String url = "jdbc:oracle:thin:@host:port:SID";
String username = "zhy";
String password = "pwd";
try {
// 1 加载驱动类
Class.forName(driver); //ojdbc6.jar使用此包该句可省略不写
// 2 获取数据库连接对象(连接指定的数据库)
conn = DriverManager.getConnection(url, username, password);
// 3 设置事务为手动提交
conn.setAutoCommit(false);
// 4 获取sql命令对象(编译和发送sql命令给数据库)
statement = conn.createStatement();
// 5 创建sql命令
String sql1 = "update student set money=money-1000 where snum=6";
String sql2 = "update student set money=money+1000 where snum=7";
// 6 执行sql命令
int i1 = statement.executeUpdate(sql1); // i >0表示sql执行成功修改的数据量,<0表示未执行成功
int i2 = statement.executeUpdate(sql2); // i >0表示sql执行成功修改的数据量,<0表示未执行成功
System.out.println("执行结果: " + i1 + "-----" + i2);
conn.commit();
//cancel()是在数据库连接的时候取消连接操作
//close()是在连接完成后,关闭这个连接
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
conn.rollback();
e.printStackTrace();
} finally {
// 7 关闭资源
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
4 JDBC 使用PrepareStatement对象完成CURD
import java.sql.*;
/*
PrepareStatement对象完成CURD
JDBC的封装,MVC思想
问题:使用Statement对象进行数据操作的时候可能会出现SQL注入的风险.
解决:使用PrepareStatement
使用:看下面注释
特点:1、防止SQL注入 2、提升SQL语句的执行效率(PrepareStatement有预编译的过程)
*/
public class TetstPrepareStatement {
public static int testPS(String uname, String upwd) {
// 声明JDBC变量,防止try catch finally 拿不到
Connection conn = null;
PreparedStatement preparedStatement = null;
// 声明JDBC参数
String driver = "oracle.jdbc.driver.OracleDriver";
String url = "jdbc:oracle:thin:@host:port:SID";
String username = "zhy";
String password = "pwd";
try {
// 加载驱动类
Class.forName(driver);
// 获取数据库连接对象
conn = DriverManager.getConnection(url, username, password);
// 设置事务为手动提交
conn.setAutoCommit(false);
// 创建sql命令
String sql = "select * from t_user where uname=? and upwd=?";
// 获取sql命令对象(编译和发送sql命令给数据库)
preparedStatement = conn.prepareStatement(sql);
// 给占位符赋值
preparedStatement.setString(1,uname);
preparedStatement.setString(2,upwd);
// 执行sql命令
int i = preparedStatement.executeUpdate(sql);
System.out.println("执行结果: " + i);
conn.commit();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
conn.rollback();
e.printStackTrace();
} finally {
// 关闭资源
try {
preparedStatement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
return i;
}
}
5 JDBC 封装
问题1:在数据库操作方法中关于驱动加载和数据库连接对象的代码是重复的。会造成修改数据源特别麻烦。
解决1:将jdbc参数在功能类中提取为全局变量
问题2:如果使用解决方式1解决后,修改了数据源则必须重启程序。而开发过程中尽量要求,在不重启程序的情况下完成对代码的参数的修改。
解决2:将jdbc参数存储到properties属性配置文件中,封装工具类进行获取。
知识点: properties文件是专门用来存储属性配置的文件,格式要求必须是键值对,以=号隔开。一行一组键值对,并且不能使用分号结尾。可以使用Properties对象来进行读取该文件的内容。
使用:
- 创建Java工具类
- 创建JDBC参数静态变量
- 创建静态代码块
3.1 创建properties对象
3.2 获取properties文件流对象
3.3 加载属性配置文件
3.4 获取JDBC参数并赋值给静态变量
3.5 加载驱动 - 创建获取Connection对象的静态方法
- 创建获取PreparedStatement对象的静态方法
- 创建获取Statement对象的静态方法
- 创建关闭资源的静态方法
- 创建增删改的封装方法 - executeDML
JDBC - 封装如下
/* UserDaoImpl */
import com.keg.JDBC.Util.JDBCUtil;
import java.sql.*;
import java.util.ArrayList;
/**
* -*- coding: utf-8 -*-
*
* @Project : BaiZhan
* @Package: com.keg.JDBC
* @Filename: UserDaoImpl.java
* @Content : JDBC增删改查封装
* @Author : HanYun.
* @Time : 2021/7/29 14:52
* @Version: 1.0
* @Software: IntelliJ IDEA
*/
public class UserDaoImpl {
/*
* @Description: 查询用户信息
* @Params: [uname, upwd]
* @ParamsType: [java.lang.String, java.lang.String]
* @return: java.util.ArrayList<com.keg.JDBC.User>
* @Author: HanYun.
* @Date:
*/
public ArrayList<User> getUserInfo(String uname, String upwd) throws ClassNotFoundException, SQLException {
// 声明User对象
User user = null;
// 声明List集合
ArrayList<User> list = new ArrayList<User>();
// 创建连接对象
Connection conn = JDBCUtil.getConnection();
// 创建sql命令
String sql = "select * from t_user where uname=? and upwd=?";
// 获取sql命令对象(编译和发送sql命令给数据库)
PreparedStatement ps = JDBCUtil.getPreparedStatement(conn, sql);
// 给占位符赋值
ps.setString(1, uname);
ps.setString(2, upwd);
// 执行sql命令
ResultSet rs = ps.executeQuery(sql);
// 遍历查询结果
while (rs.next()) {
// 创建查询数据的对象
user = new User();
user.setUnum(rs.getInt("unum"));
user.setUname(rs.getString("uname"));
user.setUname(rs.getString("uname"));
// 将对象存储到 ArrayList 中
list.add(user);
}
//关闭资源
JDBCUtil.closeAll(rs, ps, conn);
return list;
}
/*
* @Description: 新增
* @Params: []
* @ParamsType: []
* @return: int
* @Author: HanYun.
* @Date:
*/
public int insertUser() throws ClassNotFoundException, SQLException {
Connection conn = JDBCUtil.getConnection();
String sql = "insert into t_user values(?,?,?)";
PreparedStatement ps = JDBCUtil.getPreparedStatement(conn, sql);
ps.setInt(1, 1);
ps.setString(2, "zhanghanyun");
ps.setString(3, "123");
int i = ps.executeUpdate(sql);
JDBCUtil.closeAll(null, ps, conn);
return i;
}
/*
* @Description: 新增2
* @Params: []
* @ParamsType: []
* @return: int
* @Author: HanYun.
* @Date:
*/
public int insertUser2() {
String sql = "insert into t_user values(?,?,?)";
return JDBCUtil.excuteDML(sql, 20, "zhangsan", "666");
}
/*
* @Description: 更新
* @Params: [uname, unum]
* @ParamsType: [java.lang.String, int]
* @return: int
* @Author: HanYun.
* @Date:
*/
public int updateUser(String uname, int unum) throws ClassNotFoundException, SQLException {
Connection conn = JDBCUtil.getConnection();
String sql = "update t_user set uname=? where unum=?";
PreparedStatement ps = JDBCUtil.getPreparedStatement(conn, sql);
ps.setInt(1, 1);
ps.setString(2, "zhanghanyun");
ps.setString(3, "123");
int i = ps.executeUpdate(sql);
JDBCUtil.closeAll(null, ps, conn);
return i;
}
/*
* @Description: 更新2
* @Params: [uname, unum]
* @ParamsType: [java.lang.String, int]
* @return: int
* @Author: HanYun.
* @Date:
*/
public int updateUser2(String uname, int unum) throws ClassNotFoundException, SQLException {
return JDBCUtil.excuteDML("update t_user set uname=? where unum=?",uname,unum);
}
/*
* @Description: 删除
* @Params: [uname, unum]
* @ParamsType: [java.lang.String, int]
* @return: int
* @Author: HanYun.
* @Date:
*/
public int deleteUser(int unum) throws ClassNotFoundException, SQLException {
Connection conn = JDBCUtil.getConnection();
String sql = "delete t_user where unum=?";
PreparedStatement ps = JDBCUtil.getPreparedStatement(conn, sql);
ps.setInt(1, 1);
ps.setString(2, "zhanghanyun");
ps.setString(3, "123");
int i = ps.executeUpdate(sql);
JDBCUtil.closeAll(null, ps, conn);
return i;
}
/*
* @Description: 删除2
* @Params: [unum]
* @ParamsType: [int]
* @return: int
* @Author: HanYun.
* @Date:
*/
public int deleteUser2(int unum) throws ClassNotFoundException, SQLException {
return JDBCUtil.excuteDML("delete t_user where unum=?",unum);
}
}
/* JDBC.Util*/
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
/**
* -*- coding: utf-8 -*-
*
* @Project : BaiZhan
* @Package: com.keg.JDBC
* @Filename: JDBCUtil.java
* @Content :
* @Author : HanYun.
* @Time : 2021/7/29 14:31
* @Version: 1.0
* @Software: IntelliJ IDEA
*/
public class JDBCUtil {
private static String driver;
private static String url;
private static String username;
private static String password;
static {
// 创建properties对象获取属性文件的内容
Properties properties = new Properties();
// 获取属性文件的读取流对象
InputStream is = JDBCUtil.class.getResourceAsStream("/db.properties"); //动态定位位置
try {
// 加载属性配置文件
properties.load(is);
// 获取JDBC参数
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
// 加载驱动
Class.forName(driver);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
}
}
// 获取Connection对象
public static Connection getConnection() {
Connection conn = null;
try {
conn = DriverManager.getConnection(url, username, password);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return conn;
}
// 封装获取PreparedStatement对象
public static PreparedStatement getPreparedStatement(Connection conn, String sql) {
PreparedStatement ps = null;
try {
ps = conn.prepareStatement(sql);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return ps;
}
// 封装获取Statement对象
public static Statement getStatement(Connection conn, String sql) {
Statement stmt = null;
try {
stmt = conn.createStatement();
} catch (SQLException e) {
e.printStackTrace();
}
return stmt;
}
// 关闭资源
public static void closeAll(ResultSet rs, Statement stmt, Connection conn) {
try {
rs.close();
} catch (SQLException throwables) {
// 此处有空指针异常,请移步 Log4j 相关博客
throwables.printStackTrace();
}
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
// 封装DML 数据操纵语言
public static int excuteDML(String sql, Object... objects) {
Connection conn = getConnection();
PreparedStatement ps = getPreparedStatement(conn, sql);
try {
conn.setAutoCommit(false);
for (int i = 0; i < objects.length; i++) {
ps.setObject(i + 1, objects[i]);
}
int i = ps.executeUpdate();
conn.commit();
return i;
} catch (Exception throwables) {
try {
conn.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
throwables.printStackTrace();
} finally {
closeAll(null, ps, conn);
}
return -1;
}
}