JDBC介绍
JDBC(Java DataBase Connectivity)是Java和数据库之间的一个桥梁,是一个规范而不是一个实现,能够执行SQL语句。它由一组用Java语言编写的类和接口组成。各种不同类型的数据库都有相应的实现,本文中的代码都是针对MySQL数据库实现的。
固定的执行步骤:
package com.demo.connection;
import java.sql.*;
public class jdbcfirst {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");//固定写法,加载驱动
//2.用户信息和url
//useUnicode=true & characterEncoding=utf8 & useSSL=true 1.支持中文编码 2.设定字符为utf8 3.使用安全连接
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
String username = "root";
String password = "123456";
//3.连接成功,返回数据库对象 connection代表数据库
Connection connection = DriverManager.getConnection(url, username, password);
//4.执行SQL的对象 statement执行SQL的对象
Statement statement = connection.createStatement();
//5.执行SQL,可能出现结果,查看结果
String sql = "SELECT * FROM users";
//6.释放连接
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("pwd = " + resultSet.getObject("PASSWORD"));
System.out.println("email = " + resultSet.getObject("email"));
System.out.println("birth = " + resultSet.getObject("birthday"));
}
resultSet.close();
statement.close();
connection.close();
}
}
执行结果:
C:\Users\Tian\.jdks\openjdk-15.0.1\bin\java.exe "-javaagent:E:\IDEA\IntelliJ IDEA 2020.3\lib\idea_rt.jar=1299:E:\IDEA\IntelliJ IDEA 2020.3\bin" -Dfile.encoding=UTF-8 -classpath F:\code\jdbc\out\production\jdbc;F:\code\jdbc\lib\mysql-connector-java-5.1.47.jar com.demo.connection.jdbcfirst
id = 1
name = zhangsan
pwd = 123456
email = zs@sina.com
birth = 1980-12-04
id = 2
name = lisi
pwd = 123456
email = lisi@sina.com
birth = 1981-12-04
id = 3
name = wangwu
pwd = 123456
email = wangwu@sina.com
birth = 1979-12-04
Process finished with exit code 0
步骤总结:
- 加载驱动
- 连接数据库 DriverManager
- 获得执行SQL的对象 Statement
- 获得返回的结果集
- 释放连接
数据库的创建:
CREATE DATABASE `jdbcStudy` CHARACTER SET utf8 COLLATE utf8_general_ci;
USE `jdbcStudy`;
CREATE TABLE `users`(
`id` INT PRIMARY KEY,
`NAME` VARCHAR(40),
`PASSWORD` VARCHAR(40),
`email` VARCHAR(60),
birthday DATE
);
INSERT INTO users(`id`,`NAME`,`PASSWORD`,`email`,`birthday`)
VALUES(1,'zhangsan','123456','zs@sina.com','1980-12-04'),
(2,'lisi','123456','lisi@sina.com','1981-12-04'),
(3,'wangwu','123456','wangwu@sina.com','1979-12-04');
SELECT * FROM `users`;
封装:
properties代码:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true
username=root
password=123456
package com.demo.connection;
import java.io.IOException;
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");
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接
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) {
e.printStackTrace();
}
}
if (st != null) {
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
package com.demo.connection;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class second {
public static void main(String[] args) {
Connection coon = null;
Statement st = null;
ResultSet re = null;
try {
coon = JdbcUtils.getConnection();//获取数据库连接
st = coon.createStatement();//获取SQL的执行对象
String sql = "INSERT INTO users(`id`,`NAME`,`PASSWORD`,`email`,`birthday`)" +
"VALUES(4,'chuangshen','123456','cg@sina.com','1985-12-04')";
//String sql = "DELETE FROM users WHERE id=4";
int i = st.executeUpdate(sql);
if (i > 0) {
System.out.println("插入成功!!!");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.release(coon, st, re);
}
}
}
SQL的注入:
SQL存在漏洞,会被攻击导致数据泄露。
SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。
package com.demo.connection;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import static com.kuang.lesson02.utils.JdbcUtils.getConnection;
public class SQL注入 {
public static void main(String[] args) {
//SQL注入
login("' or '1=1","123456");
}
public static void login(String name,String password){
Connection conn =null;
Statement st = null;
ResultSet rs =null;
try {
conn = getConnection();//获取连接
st = conn.createStatement();//获取SQL执行对象
String sql = "select * from users where `NAME`='"+ name +"' AND `PASSWORD`='"+ password +"'" ;
rs=st.executeQuery(sql);//查询完毕返回结果集
while (rs.next()){
System.out.println(rs.getString("NAME"));
}
JdbcUtils.release(conn,st,rs);
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
JdbcUtils.release(conn,st,rs);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
PreparedStatement对象
PreparedStatement 可以防止SQL注入 ,效率更高。
package com.demo.connection;
import java.sql.*;
import java.util.Date;
public class third {
public static void main(String[] args) {
Connection coon = null;
PreparedStatement st = null;
ResultSet re = null;
try {
coon = JdbcUtils.getConnection();//获取数据库连接
String sql = "INSERT INTO users(`id`,`NAME`,`PASSWORD`,`email`,`birthday`) values (?,?,?,?,?)";
st = coon.prepareStatement(sql);//预编译SQL
//prepareStatement 放置SQL注入的本质,把传递进来的参数当作字符
//假设其中存在转移字符,比如说' 会被直接转义
//手动给参数赋值
st.setObject(1, 4);
st.setObject(2, "fyp");
st.setObject(3, "123456");
st.setObject(4, "123@qq.com");
//注意点:SQL: sql.Date
//Java: util.Date new Date().getTime()获得时间戳
st.setDate(5, new java.sql.Date(new Date().getTime()));
//执行
int i = st.executeUpdate();
if (i > 0) {
System.out.println("插入成功!!!");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.release(coon, st, re);
}
}
}
使用IDEA连接数据库
出现Server returns invalid timezone. Need to set ‘serverTimezone’ property.是时区设置出现问题。解决办法。
事务
-- mysql 自动开启事务提交
SET autocommit=0 -- 关闭
SET autocommit=1 -- 开启(默认的)
-- 手动处理事务
SET autocommit =0 -- 关闭自动提交
-- 事务开启
START TRANSACTION -- 标记一个事务的开始,从这个之后的SQP都在同一个事务内
INSERT XX
INSERT XX
-- 提交 : 持久化(成功)
COMMIT
-- 回滚: 回到原来的样子(失败)
ROLLBACK
-- 事务结束
SET autocommit = 1 -- 开启自动提交
-- 了解
SAVEPOINT 保存点名称 -- 设置一个事务的保存点
ROLLBACK TO SAVEPOINT 保存点名 -- 回滚到保存点
RELEASE SAVEPOINT 保存点 -- 删除保存点
模拟转账的场景
CREATE DATABASE shop CHARACTER SET utf8 COLLATE utf8_general_ci
USE shop
CREATE TABLE `account` (
`id` INT (3) NOT NULL AUTO_INCREMENT,
`name` VARCHAR (30) NOT NULL,
`money` DECIMAL (9, 2) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE = INNODB DEFAULT CHARSET = utf8
INSERT INTO account (`name`, `money`)
VALUES
('A', 2000),
('B', 10000) -- 模拟转账:事务
SET autocommit = 0 ;
-- 关闭自动提交
START TRANSACTION -- 开启事务(一组事务)
UPDATE account SET money = money-500 WHERE `name` = 'A' -- A 转账给B
UPDATE account SET money = money+500 WHERE `name` = 'B' -- B 收到钱
COMMIT ; -- 提交事务
ROLLBACK ; -- 回滚
SET autocommit = 1 -- 恢复默认值
JDBC的事务
- 开启事务conn.setAutoCommit(false)
- 一组业务执行完毕,提交事务
- 可以在catch语句中显示的定义回滚,但是默认失败会回滚
package com.demo.connection;
import com.kuang.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Action {
public static void main(String[] args) {
Connection conn =null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
//关闭数据库的自动提交功能, 开启事务
conn.setAutoCommit(false);
//自动开启事务
String sql = "update account set money = money-500 where id = 1";
ps =conn.prepareStatement(sql);
ps.executeUpdate();
String sql2 = "update account set money = money-500 where id = 2";
ps=conn.prepareStatement(sql2);
ps.executeUpdate();
//业务完毕,提交事务
conn.commit();
System.out.println("操作成功");
} catch (Exception e) {
try {
//如果失败,则默认回滚
conn.rollback();//如果失败,回滚
} catch (SQLException throwables) {
throwables.printStackTrace();
}
e.printStackTrace();
}finally {
try {
JdbcUtils.release(conn,ps,rs);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
数据库连接池
数据库连接–执行完毕–释放
连接–释放 十分浪费资源
池化技术: 准备一些预先的资源,过来就连接预先准备好的
常用连接数 100
最少连接数:100
最大连接数 : 120 业务最高承载上限
排队等待
等待超时:100ms
编写连接池,实现一个接口 DateSource