1.JDBC(重点)
1.1 数据库驱动
驱动: 程序会通过驱动操作数据库
1.2 JDBC
SUN 公司为了简化开发人员的操作, 对数据库的操作提供了统一的Java操作数据库的规范, 简称JDBC
这些规范的实现由具体的厂商去做.
对于开发人员来说, 只需要掌握JDBC的操作即可.
java.sql
javax.sql
还需要导入一个数据库驱动包. 到MySQL官网下载
1.3 第一个JDBC程序
创建测试数据库
1.创建一个普通项目
package lesson01;
import java.sql.*;
public class JdbcFirstLesson {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 1. 加载驱动
Class.forName("com.mysql.jdbc.Driver"); // 固定写法, 加载驱动
// 2. 用户信息和url
// useUnicode=true&characterEncoding=utf8&useSSL=true 使用编码,使用什么编码,使用安全的连接
// MySQL8.0 url后面要加时区serverTimezone = UTC
String url = "jdbc:mysql://localhost:3306/"+"school"+"?useUnicode=true&characterEncoding=utf8&useSSL=false";
String username = "root";
String password = "liver1225";
// 3. 连接成功, 数据库对象 Connection 代表数据库
Connection connection = DriverManager.getConnection(url, username, password);
// 4. 执行 SQL的 读写对象 Statement
Statement statement = connection.createStatement();
// 5. 对象去执行SQL, 可能存在结果, 查看
String sql = "Select * from student";
ResultSet resultSet = statement.executeQuery(sql); // 返回的结果结合, 封装了全部的查询结果
while( resultSet.next()){
System.out.println("id="+resultSet.getObject("id"));
System.out.println("name="+resultSet.getObject("name"));
System.out.println("birthday="+resultSet.getObject("birthday"));
System.out.println("=================================================");
}
// 6. 释放连接 倒着来
resultSet.close();
statement.close();
connection.close();
}
}
步骤总结:
- 加载驱动 Class.ForName
- 连接数据库 DriverManager
- 获得执行sql的对象 statement(unsafe)
- 获得返回的结果集(查询)
- 释放连接
DriverManager
// 1. 加载驱动
//DriverManager.registerDriver(new com.mysql.jdbc.Driver()); // 不推荐
Class.forName("com.mysql.jdbc.Driver"); // 固定写法, 加载驱动
// connection 代表数据库
Connection connection = DriverManager.getConnection(url, username, password);
// 事务回滚
// 事务提交
// 数据库设置自动提交
connection.rollback();
connection.commit();
connection.setAutoCommit(true);
URL
String url = "jdbc:mysql://localhost:3306/"+"school"+"?useUnicode=true&characterEncoding=utf8&useSSL=false";
// mysql --3306
//jdbc:mysql://主机地址:端口号//数据库名?参数名?参数1&参数2&参数3
Statement 执行SQL的对象, prepareStatement 执行SQL的对象
// 编写SQL
statement.executeQuery(); // 查询操作返回 ResultSet
statement.execute(); // 执行任何SQL
statement.executeUpdate(); // 更新, 插入, 删除. 都是用这个, 返回一个受影响的行数
ResultSet 查询的结果集: 封装了所有的查询结果
获得指定的数据类型
resultSet.getObject(); // 在不知指定类型的情况下
// 在知道指定类型的情况下
resultSet.getString();
resultSet.getInt();
resultSet.getFloat();
resultSet.getDate();
resultSet.getObject();
遍历.指定
resultSet.beforeFirst();// 移动到最前面
resultSet.afterLast();// 移动到最后面
resultSet.next();// 移动到下一个 数据
resultSet.previous();// 移动到前一行 数据
resultSet.absolute();// 移动到指定行
释放资源
// 6. 释放连接 倒着来
resultSet.close();
statement.close();
connection.close();
1.4 Statement

CRUD操作-create
CRUD操作-delete
CRUD操作-update
CRUD操作-query

executeQuery更好
代码实现:
提取工具类
package lesson02.utils;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils {
private static String driver = null;
private static String url = null;
private static String username = null;
private static String password = null;
static {
try{
InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties"); // 输入流
Properties properties = new Properties();
properties.load(in); // 加载属性
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
//1.驱动只用加载一次
Class.forName(driver);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// 获取连接
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, username, password);
}
// 释放连接资源
public static void release(Connection conn, Statement st, ResultSet rs){
if (rs!=null){
try {
rs.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
if(st!=null){
try {
st.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
}
2.编写增删改的方法, executeUpdate
// 增
package lesson02;
import lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestInsert {
public static void main(String[] args) throws SQLException {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection(); // 获取数据库连接
st = conn.createStatement();// 获得sql的执行对象
String sql = "Insert Into student(id, `name`, `birthday`)" + "Values(4, 'ch', '1998-06-06 19:46:22.0')";
int i = st.executeUpdate(sql);
if(i>0){
System.out.println("insert success!");
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.release(conn,st, rs);
}
}
}
// 删
package lesson02;
import lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestDelete {
public static void main(String[] args) throws SQLException {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection(); // 获取数据库连接
st = conn.createStatement();// 获得sql的执行对象
String sql = "Delete From student Where id = 4";
int i = st.executeUpdate(sql);
if(i>0){
System.out.println("delete success!");
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.release(conn,st, rs);
}
}
}
// 改
package lesson02;
import lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestUpdate {
public static void main(String[] args) throws SQLException {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection(); // 获取数据库连接
st = conn.createStatement();// 获得sql的执行对象
String sql = "Update student Set `name`='ch',`birthday`='1998-06-05 19:46:22.0' where id=1";
int i = st.executeUpdate(sql);
if(i>0){
System.out.println("update success!");
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.release(conn,st, rs);
}
}
}
//查
package lesson02;
import lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestSelect {
public static void main(String[] args) {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
// SQL
String sql = "Select * From student Where id = 1";
rs = st.executeQuery(sql); //查询 完毕 会返回结果集
while(rs.next()){
System.out.println(rs.getString("name"));
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
SQL注入的问题
sql存在问题, 会被攻击导致数据泄露 sql会被拼接 or
指web应用对用户输入数据的合法性没有判断或过滤不严.
package lesson02;
import lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class SQLzhuru {
public static void main(String[] args) {
// login("ch", "1"); // 正常指令
login(" 'or '1=1", " 'or '1=1"); // 攻击注入
}
// 登录业务
public static void login(String username, String password) {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
// SQL
String sql = "Select * From student Where `name`= '" + username + "' AND `id`='" + password + "'";
rs = st.executeQuery(sql); //查询 完毕 会返回结果集
while (rs.next()) {
System.out.println(rs.getString("name"));
System.out.println(rs.getInt("id"));
System.out.println("==============================");
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
JdbcUtils.release(conn, st, rs);
}
}
}
1.5 PreparedStatement 对象
它可以防止SQL注入, 并且效率更高!
1)增
package lesson03;
import lesson02.utils.JdbcUtils;
import java.sql.*;
public class TestInsert {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pst = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection(); // 获取数据库连接
// 区别
String sql = "Insert Into student(id, `name`, `birthday`)" + "Values(?, ?, ?)"; //使用?占位符代替参数
pst = conn.prepareStatement(sql);// 预编译sql, 先写sql, 如然后不执行
// 手动给参数赋值
pst.setInt(1, 3); // id
pst.setString(2, "wzc"); // name
// 注意点: sql.Date 和 utils.Date
pst.setDate(3, new java.sql.Date(new java.util.Date().getTime())); // birthday
int i = pst.executeUpdate(); // 已经预编译过了
if(i>0){
System.out.println("insert success!");
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.release(conn, pst, null);
}
}
}
2)删
package lesson03;
import lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestDelete {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pst = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection(); // 获取数据库连接
// 区别
String sql = "Delete From student Where id = ?"; //使用?占位符代替参数
pst = conn.prepareStatement(sql);// 预编译sql, 先写sql, 如然后不执行
// 手动给参数赋值
pst.setInt(1, 3); // id
int i = pst.executeUpdate(); // 已经预编译过了
if(i>0){
System.out.println("delete success!");
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.release(conn, pst, null);
}
}
}
3)改
package lesson03;
import lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestUpdate {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pst = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection(); // 获取数据库连接
// 区别
String sql = "Update student Set `name`=?,`birthday`=? where id=?"; //使用?占位符代替参数
pst = conn.prepareStatement(sql);// 预编译sql, 先写sql, 如然后不执行
// 手动给参数赋值
pst.setString(1, "wzc"); // name
// 注意点: sql.Date 和 utils.Date
pst.setDate(2, new java.sql.Date(new java.util.Date().getTime())); // birthday
pst.setInt(3, 1); // id
int i = pst.executeUpdate(); // 已经预编译过了
if(i>0){
System.out.println("update success!");
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.release(conn, pst, null);
}
}
}
4)查
package lesson03;
import lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestSelect {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pst = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection(); // 获取数据库连接
// 区别
String sql = "Select * From student Where id = ?"; //使用?占位符代替参数
pst = conn.prepareStatement(sql);// 预编译sql, 先写sql, 如然后不执行
// 手动给参数赋值
pst.setInt(1, 1); // id
rs = pst.executeQuery();
while(rs.next()){
System.out.println(rs.getString("name"));
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.release(conn, pst, null);
}
}
}
5)防止sql注入
package lesson03;
import lesson02.utils.JdbcUtils;
import java.sql.*;
public class SQLzhuru {
public static void main(String[] args) {
// login("wzc", "1"); // 正常指令
login(" '' or 1=1", " '' or 1=1"); // 攻击注入, 此时就不会报错了
}
// 登录业务
public static void login(String username, String password) {
Connection conn = null;
PreparedStatement pst = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
// SQL 防止注入攻击的本质, 把传递进来的参数当成字符
// 假设其中存在转义字符, 比如说' 会被直接转义.
String sql = "Select * From student Where `name`=? and `id`=?"; //Mybatis
pst = conn.prepareStatement(sql);
pst.setString(1, username);
pst.setString(2, password);
rs = pst.executeQuery(); //查询 完毕 会返回结果集
while (rs.next()) {
System.out.println(rs.getString("name"));
System.out.println(rs.getInt("id"));
System.out.println("==============================");
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
JdbcUtils.release(conn, pst, rs);
}
}
}
1.6 使用IDEA连接数据库
1.7 事务
要么都成功,要么都失败
ACID原则
代码实现
package lesson04;
import lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestTransaction {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pst = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection(); // 获取数据库连接
// 关闭自动提交==开启事务
conn.setAutoCommit(false);
String sql1 = "Update account set money=money-100 where NAME = 'A'";
pst = conn.prepareStatement(sql1);
pst.executeUpdate();
// int x = 1/0; // 失败语句
String sql2 = "Update account set money=money+100 where NAME = 'B'";
pst = conn.prepareStatement(sql2);
pst.executeUpdate();
// 业务完毕, 提交事务
conn.commit();
System.out.println("成功");
} catch (SQLException e) {
try{
conn.rollback(); // 失败了会回滚, 但是默认就是会回滚的
}catch (SQLException e1){
e1.printStackTrace();
} throw new RuntimeException(e);
} finally {
JdbcUtils.release(conn, pst, rs);
}
}
}
关键语句:
1.开启事务 conn.setAutoCommmit(false);
2.一组业务执行完毕, 提交事务
3.可以在catch语句中显式得定义 回滚语句, 但默认失败会回滚
1.8 数据库连接池
数据库连接—执行完毕—释放
连接—释放 十分浪费系统资源
池化技术:准备一些预先的资源, 先连接预先准备好的
编写连接池,只需要实现一个接口:DataSource
开源数据源实现
DBCP
C3P0
Druid:阿里巴巴,已放弃
使用了这些数据库连接池后, 就不需要编写连接数据库的代码
DBCP
需要用到的jar包:commons-dbcp-1.4
C3P0
导如jar包即可.
结论: 无论使用什么数据源, 本质还是一样的. 接口DataSource不会变




9141

被折叠的 条评论
为什么被折叠?



