1、JDBC
1.1、数据库驱动
这里的驱动的概念和平时听到的那种驱动的概念是一样的,比如平时购买的声卡,网卡直接插到计算机 上面是不能用的,必须要安装相应的驱动程序之后才能够使用声卡和网卡,同样道理,我们安装好数据库之后,我们的应用程序也是不能直接使用数据库的,必须要通过相应的数据库驱动程序,通过驱动程序去和数据库打交道,如下所示:
1.2、JDBC 介绍
SUN 公司为了简化、统一对数据库的操作,定义了一套 Java 操作数据库的规范(接口),称之为 JDBC。这套接口由数据库厂商去实现,这样,开发人员只需要学习 jdbc 接口,并通过 jdbc 加载具体的驱动,就可以操作数据库。如下图所示:
JDBC 全称为:Java Data Base Connectivity(java 数据库连接),它主要由接口组成。组成 JDBC 的2个包:java.sql、javax.sql 开发 JDBC 应用需要以上 2 个包的支持外,还需要导入相应 JDBC 的数据库实现(即数据库驱动)。
1.3 、面试问题?
1.4、编写 JDBC 程序
搭建实验环境
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,'zhansan','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');
复制代码
新建一个 Java 工程,并导入数据驱动
编写程序从 user 表中读取数据,并打印在命令行窗口中。
package com.kuang.lesson01;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class JdbcFirstDemo {
public static void main(String[] args) throws Exception {
//要连接的数据库URL
String url = "jdbc:mysql://localhost:3306/jdbcStudy?
useUnicode=true&characterEncoding=utf8&useSSL=true";
//连接的数据库时使用的用户名
String username = "root";
//连接的数据库时使用的密码
String password = "123456";
//1.加载驱动
//DriverManager.registerDriver(new com.mysql.jdbc.Driver());不推荐使用
这种方式来加载驱动
Class.forName("com.mysql.jdbc.Driver");//推荐使用这种方式来加载驱动
//2.获取与数据库的链接
Connection conn = DriverManager.getConnection(url, username,
password);
//3.获取用于向数据库发送sql语句的statement
Statement st = conn.createStatement();
String sql = "select id,name,password,email,birthday from users";
//4.向数据库发sql,并获取代表结果集的resultset
ResultSet rs = st.executeQuery(sql);
//5.取出结果集的数据
while(rs.next()){
System.out.println("id=" + rs.getObject("id"));
System.out.println("name=" + rs.getObject("name"));
System.out.println("password=" + rs.getObject("password"));
System.out.println("email=" + rs.getObject("email"));
System.out.println("birthday=" + rs.getObject("birthday"));
}
//6.关闭链接,释放资源
rs.close();
st.close();
conn.close();
}
}
复制代码
1.5、对象说明
DriverManager 类讲解
Jdbc 程序中的 DriverManager 用于加载驱动,并创建与数据库的链接,这个 API 的常用方法:
DriverManager.registerDriver(new Driver())
DriverManager.getConnection(url, user, password)
复制代码
注意:在实际开发中并不推荐采用 registerDriver 方法注册驱动。原因有二:
查看 Driver 的源代码可以看到,如果采用此种方式,会导致驱动程序注册两次,也就是在内存中会有两个 Driver 对象。
程序依赖 mysql 的 api,脱离 mysql 的 jar 包,程序将无法编译,将来程序切换底层数据库将会非常麻烦。
推荐方式:Class.forName("com.mysql.jdbc.Driver");采用此种方式不会导致驱动对象在内存中重复出现,并且采用此种方式,程序仅仅只需要一个字符串,不需要依赖具体的驱动,使程序的灵活性更高。
数据库 URL 讲解
URL 用于标识数据库的位置,通过 URL 地址告诉 JDBC 程序连接哪个数据库,URL 的写法为:
常用数据库 URL 地址的写法:
Oracle 写法:jdbc:oracle:thin:@localhost:1521:sid
SqlServer 写法:jdbc:microsoft:sqlserver://localhost:1433; DatabaseName=sid
MySql 写法:jdbc:mysql://localhost:3306/sid
如果连接的是本地的 Mysql 数据库,并且连接使用的端口是 3306,那么的 url 地址可以简写为:jdbc:mysql:///数据
Connection 类讲解
Jdbc 程序中的 Connection,它用于代表数据库的链接,Collection 是数据库编程中最重要的一个对象,客户端与数据库所有交互都是通过 connection 对象完成的,这个对象的常用方法:
createStatement():创建向数据库发送 sql 的 statement 对象。
prepareStatement(sql) :创建向数据库发送预编译 sql 的 PrepareSatement 对象。
setAutoCommit(boolean autoCommit):设置事务是否自动提交。
commit() :在链接上提交事务。
rollback() :在此链接上回滚事务。
Statement 类讲解
Jdbc 程序中的 Statement 对象用于向数据库发送 SQL 语句, Statement 对象常用方法:
executeQuery(String sql) :用于向数据发送查询语句。
executeUpdate(String sql):用于向数据库发送 insert、update 或 delete 语句
execute(String sql):用于向数据库发送任意 sql 语句
addBatch(String sql) :把多条 sql 语句放到一个批处理中。
executeBatch():向数据库发送一批 sql 语句执行。
ResultSet 类讲解
Jdbc 程序中的 ResultSet 用于代表 Sql 语句的执行结果。Resultset 封装执行结果时,采用的类似于表格的方式。ResultSet 对象维护了一个指向表格数据行的游标,初始的时候,游标在第一行之前,调用 ResultSet.next() 方法,可以使游标指向具体的数据行,进行调用方法获取该行的数据。
ResultSet 既然用于封装执行结果的,所以该对象提供的都是用于获取数据的 get 方法:
ResultSet 还提供了对结果集进行滚动的方法:
释放资源
Jdbc 程序运行完后,切记要释放程序在运行过程中,创建的那些与数据库进行交互的对象,这些对象通常是 ResultSet, Statement 和 Connection 对象,特别是 Connection 对象,它是非常稀有的资源,用完后必须马上释放,如果 Connection 不能及时、正确的关闭,极易导致系统宕机。Connection 的使用原则是尽量晚创建,尽量早的释放。
为确保资源释放代码能运行,资源释放代码也一定要放在 finally 语句中。
1.6、statement 对象
Jdbc 中的 statement 对象用于向数据库发送 SQL 语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。
Statement 对象的 executeUpdate 方法,用于向数据库发送增、删、改的 sql 语句,executeUpdate 执行完后,将会返回一个整数(即增删改语句导致了数据库几行数据发生了变化)。
Statement.executeQuery 方法用于向数据库发送查询语句,executeQuery 方法返回代表查询结果的 ResultSet 对象。
CRUD 操作-create
使用 executeUpdate(String sql)方法完成数据添加操作,示例操作:
Statement st = conn.createStatement();
String sql = "insert into user(….) values(…..) ";
int num = st.executeUpdate(sql);
if(num>0){
System.out.println("插入成功!!!");
}
复制代码
CRUD 操作-delete
使用 executeUpdate(String sql)方法完成数据删除操作,示例操作:
Statement st = conn.createStatement();
String sql = "delete from user where id=1";
int num = st.executeUpdate(sql);
if(num>0){
System.out.println(“删除成功!!!");
}
复制代码
CRUD 操作-update
使用 executeUpdate(String sql)方法完成数据修改操作,示例操作:
Statement st = conn.createStatement();
String sql = "update user set name='' where name=''";
int num = st.executeUpdate(sql);
if(num>0){
System.out.println(“修改成功!!!");
}
复制代码
CRUD 操作-read
使用 executeQuery(String sql)方法完成数据查询操作,示例操作:
Statement st = conn.createStatement();
String sql = "select * from user where id=1";
ResultSet rs = st.executeUpdate(sql);
while(rs.next()){
//根据获取列的数据类型,分别调用rs的相应方法映射到java对象中
}
复制代码
使用 jdbc 对数据库增删改查 1、新建一个 lesson02 的包 2、在 src 目录下创建一个 db.properties 文件,如下图所示:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcStudy?
useUnicode=true&characterEncoding=utf8&useSSL=true
username=root
password=123456
复制代码
3、在 lesson02 下新建一个 utils 包,新建一个类 JdbcUtils
package com.kuang.lesson02.utils;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
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{
//读取db.properties文件中的数据库连接信息
InputStream in =
JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
Properties prop = new Properties();
prop.load(in);
//获取数据库连接驱动
driver = prop.getProperty("driver");
//获取数据库连接URL地址
url = prop.getProperty("url");
//获取数据库连接用户名
username = prop.getProperty("username");
/获取数据库连接密码
password = prop.getProperty("password");
//加载数据库驱动
Class.forName(driver);
}catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
// 获取数据库连接对象
public static Connection getConnection() throws SQLException{
return DriverManager.getConnection(url, username,password);
}
// 释放资源,要释放的资源包括Connection数据库连接对象,负责执行SQL命令的Statement 对象,存储查询结果的ResultSet对象
public static void release(Connection conn,Statement st,ResultSet rs){
if(rs!=null){
try{
//关闭存储查询结果的ResultSet对象
rs.close();
}catch (Exception e) {
e.printStackTrace();
}
rs = null;
}
if(st!=null){
try{
//关闭负责执行SQL命令的Statement对象
st.close();
}catch (Exception e) {
e.printStackTrace();
}
}
if(conn!=null){
try{
//关闭Connection数据库连接对象
conn.close();
}catch (Exception e) {
e.printStackTrace();
}
}
}
}
复制代码
使用 statement 对象完成对数据库的 CRUD 操作
1、插入一条数据
package com.kuang.lesson02;
import com.kuang.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
public class TestInsert {
public static void main(String[] args) {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try{
//获取一个数据库连接
conn = JdbcUtils.getConnection();
//通过conn对象获取负责执行SQL命令的Statement对象
st = conn.createStatement();
//要执行的SQL命令
String sql = "insert into users(id,name,password,email,birthday) " +
"values(4,'kuangshen','123','24736743@qq.com','2020-01-
01')";
//执行插入操作,executeUpdate方法返回成功的条数
int num = st.executeUpdate(sql);
if(num>0){
System.out.println("插入成功!!");
}
}catch (Exception e) {
e.printStackTrace();
}finally{
//SQL执行完成之后释放相关资源
JdbcUtils.release(conn, st, rs);
}
}
}
复制代码
2、删除一条数据
package com.kuang.lesson02;
import com.kuang.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
public class TestDelete {
public static void main(String[] args) {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection();
String sql = "delete from users where id=4";
st = conn.createStatement();
int num = st.executeUpdate(sql);
if(num>0){
System.out.println("删除成功!!");
}catch (Exception e) {
e.printStackTrace();
}finally{
JdbcUtils.release(conn, st, rs);
}
}
}
复制代码
3、更新一条数据
package com.kuang.lesson02;
import com.kuang.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
public class TestUpdate {
public static void main(String[] args) {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection();
String sql = "update users set
name='kuangshen',email='24736743@qq.com' where id=3";
st = conn.createStatement();
int num = st.executeUpdate(sql);
if(num>0){
System.out.println("更新成功!!");
}
}catch (Exception e) {
e.printStackTrace();
}finally{
JdbcUtils.release(conn, st, rs);
}
}
}
复制代码
4、查询数据
package com.kuang.lesson02;
import com.kuang.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
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();
String sql = "select * from users where id=3";
st = conn.createStatement();
rs = st.executeQuery(sql);
if(rs.next()){
System.out.println(rs.getString("name"));
}
}catch (Exception e) {
e.printStackTrace();
}finally{
JdbcUtils.release(conn, st, rs);
}
}
复制代码
SQL 注入问题
通过巧妙的技巧来拼接字符串,造成SQL短路,从而获取数据库数据
package com.kuang.lesson02;
import com.kuang.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
public class SQL注入 {
public static void main(String[] args) {
// login("zhangsan","123456"); // 正常登陆
login("'or '1=1","123456"); // SQL 注入
}
public static void login(String username,String password){
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection();
// select * from users where name='' or '1=1' and password = '123456'
String sql = "select * from users where name='"+username+"' and
password='"+password+"'";
st = conn.createStatement();
rs = st.executeQuery(sql);
while(rs.next()){
System.out.println(rs.getString("name"));
System.out.println(rs.getString("password"));
System.out.println("==============");
}
}catch (Exception e) {
e.printStackTrace();
}finally{
JdbcUtils.release(conn, st, rs);
}
}
}
复制代码
1.7 、PreparedStatement 对象
PreperedStatement 是 Statement 的子类,它的实例对象可以通过调用 Connection.preparedStatement()方法获得,相对于 Statement 对象而言:PreperedStatement 可以避免 SQL 注入的问题。
Statement 会使数据库频繁编译 SQL,可能造成数据库缓冲区溢出。
PreparedStatement 可对 SQL 进行预编译,从而提高数据库的执行效率。并且 PreperedStatement 对于 sql 中的参数,允许使用占位符的形式进行替换,简化 sql 语句的编写。
使用 PreparedStatement 对象完成对数据库的 CRUD 操作
1、插入数据
package com.kuang.lesson03;
import com.kuang.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.util.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class TestInsert {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try{
//获取一个数据库连接
conn = JdbcUtils.getConnection();
//要执行的SQL命令,SQL中的参数使用?作为占位符
String sql = "insert into users(id,name,password,email,birthday) values(?,?,?,?,?)";
//通过conn对象获取负责执行SQL命令的prepareStatement对象
st = conn.prepareStatement(sql);
//为SQL语句中的参数赋值,注意,索引是从1开始的
st.setInt(1, 4);//id是int类型的
st.setString(2, "kuangshen");//name是varchar(字符串类型)
st.setString(3, "123");//password是varchar(字符串类型)
st.setString(4, "24736743@qq.com");//email是varchar(字符串类型)
st.setDate(5, new java.sql.Date(new
Date().getTime()));//birthday是date类型
//执行插入操作,executeUpdate方法返回成功的条数
int num = st.executeUpdate();
if(num>0){
System.out.println("插入成功!!");
}
}catch (Exception e) {
e.printStackTrace();
}finally{
//SQL执行完成之后释放相关资源
JdbcUtils.release(conn, st, rs);
}
}
}
复制代码
2、删除一条数据
package com.kuang.lesson03;
import com.kuang.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class TestDelete {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection();
String sql = "delete from users where id=?";
st = conn.prepareStatement(sql);
st.setInt(1, 4);
int num = st.executeUpdate();
if(num>0){
System.out.println("删除成功!!");
}
}catch (Exception e) {
e.printStackTrace();
}finally{
JdbcUtils.release(conn, st, rs);
}
}
}
复制代码
3、更新一条数据
package com.kuang.lesson03;
import com.kuang.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class TestUpdate {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection();
String sql = "update users set name=?,email=? where id=?";
st = conn.prepareStatement(sql);
st.setString(1, "kuangshen");
st.setString(2, "24736743@qq.com");
st.setInt(3, 2);
int num = st.executeUpdate();
if(num>0){
System.out.println("更新成功!!");
}
}catch (Exception e) {
e.printStackTrace();
}finally{
JdbcUtils.release(conn, st, rs);
}
}
}
复制代码
4、查询一条数据
package com.kuang.lesson03;
import com.kuang.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class TestSelect {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection();
String sql = "select * from users where id=?";
st = conn.prepareStatement(sql);
st.setInt(1, 1);
rs = st.executeQuery();
if(rs.next()){
System.out.println(rs.getString("name"));
}
}catch (Exception e) {
}finally{
JdbcUtils.release(conn, st, rs);
}
}
}
复制代码
避免 SQL 注入
package com.kuang.lesson03;
import com.kuang.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
public class SQL注入 {
public static void main(String[] args) {
// login("zhangsan","123456"); // 正常登陆
login("'or '1=1","123456"); // SQL 注入
}
public static void login(String username,String password){
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection();
// select * from users where name='' or '1=1' and password = '123456'
String sql = "select * from users where name=? and password=?";
st = conn.prepareStatement(sql);
st.setString(1,username);
st.setString(2,password);
rs = st.executeQuery();
while(rs.next()){
System.out.println(rs.getString("name"));
System.out.println(rs.getString("password"));
System.out.println("==============");
}
}catch (Exception e) {
e.printStackTrace();
}finally{
JdbcUtils.release(conn, st, rs);
}
}
}
复制代码
原理:执行的时候参数会用引号包起来,并把参数中的引号作为转义字符,从而避免了参数也作为条件的一部分
2、javaweb-jdbc
什么是 JDBC : Java 连接数据库!
需要 jar 包的支持:
实验环境搭建
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,'张三','123456','zs@qq.com','2000-01-01');
INSERT INTO users(id,`name`,`password`,email,birthday)
VALUES(2,'李四','123456','ls@qq.com','2000-01-01');
INSERT INTO users(id,`name`,`password`,email,birthday)
VALUES(3,'王五','123456','ww@qq.com','2000-01-01');
SELECT * FROM users
复制代码
导入数据库依赖
<!--mysql的驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
复制代码
IDEA 中连接数据库:
JDBC 固定步骤:
加载驱动
连接数据库,代表数据库
向数据库发送 SQL 的对象 Statement : CRUD
编写 SQL (根据业务,不同的 SQL)
执行 SQL
关闭连接
public class TestJdbc {
public static void main(String[] args) throws ClassNotFoundException,SQLException {
//配置信息
//useUnicode=true&characterEncoding=utf-8 解决中文乱码
String url="jdbc:mysql://localhost:3306/jdbc?
useUnicode=true&characterEncoding=utf-8";
String username = "root";
String password = "123456";
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.连接数据库,代表数据库
Connection connection = DriverManager.getConnection(url, username,password);
//3.向数据库发送SQL的对象Statement,PreparedStatement : CRUD
Statement statement = connection.createStatement();
//4.编写SQL
String sql = "select * from users";
//5.执行查询SQL,返回一个 ResultSet : 结果集
ResultSet rs = statement.executeQuery(sql);
while (rs.next()){
System.out.println("id="+rs.getObject("id"));
System.out.println("name="+rs.getObject("name"));
System.out.println("password="+rs.getObject("password"));
System.out.println("email="+rs.getObject("email"));
System.out.println("birthday="+rs.getObject("birthday"));
}
//6.关闭连接,释放资源(一定要做) 先开后关
rs.close();
statement.close();
connection.close();
}
}
复制代码
预编译 SQL
public class TestJDBC2 {
public static void main(String[] args) throws Exception {
//配置信息
//useUnicode=true&characterEncoding=utf-8 解决中文乱码
String url="jdbc:mysql://localhost:3306/jdbc?
useUnicode=true&characterEncoding=utf-8";
String username = "root";
String password = "123456";
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.连接数据库,代表数据库
Connection connection = DriverManager.getConnection(url, username, password);
//3.编写SQL
String sql = "insert into users(id, name, password, email,
birthday) values (?,?,?,?,?);";
//4.预编译
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1,2);//给第一个占位符? 的值赋值为1;
preparedStatement.setString(2,"狂神说Java");//给第二个占位符? 的值赋值为 狂神说Java;
preparedStatement.setString(3,"123456");//给第三个占位符? 的值赋值为 123456;
preparedStatement.setString(4,"24736743@qq.com");//给第四个占位符? 的 值赋值为1;
preparedStatement.setDate(5,new Date(new
java.util.Date().getTime()));//给第五个占位符? 的值赋值为new Date(new java.util.Date().getTime());
//5.执行SQL
int i = preparedStatement.executeUpdate();
if (i>0){
System.out.println("插入成功@");
}
//6.关闭连接,释放资源(一定要做) 先开后关
preparedStatement.close();
connection.close();
}
}
复制代码
事务要么都成功,要么都失败!ACID 原则:保证数据的安全。
开启事务
事务提交 commit()
事务回滚 rollback()
关闭事务
转账:
A:1000
B:1000
A(900) --100--> B(1100)
复制代码
Junit 单元测试依赖
<!--单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
复制代码
简单使用 @Test 注解只有在方法上有效,只要加了这个注解的方法,就可以直接运行!
@Test
public void test(){
System.out.println("Hello");
}
复制代码
失败的时候是红色:
学习视频:https://www.bilibili.com/video/BV12J411M7Sj?from=search&seid=1533808106467763271&spm_id_from=333.337.0.0
评论