一、JDBC是什么?
Java DataBase Connectivity(Java语言连接数据库)
二、JDBC的本质是什么?
JDBC是SUN公司制定的一套接口(interface)。
接口都有调用者和实现者。
面向接口调用、面向接口写实现类,这都属于面向接口编程。
三、为什么要面向接口编程?
解耦合:降低程序的耦合度,提高程序的扩展力。
多态机制就是非常典型的:面向抽象编程。(不要面向具体编程)
(这里需要画图带大家理解。。。)
四、为什么SUN制定一套JDBC接口呢?
因为每一个数据库产品都有自己独特的实现原理
五、JDBC编程六步(需要背会)
1.注册驱动(告诉Java程序,即将连接的是哪个品牌的数据库)
2.获取连接(表示JVM的进程和数据库进程之间的通道打开了,这属于进程之间的通信,使用完后记得关闭通道)。
3.获取数据库操作对象(专门执行sql语句的对象)
4.执行SQL语句(DQL,DML…)
5.处理查询结果集 (只有当第四步执行的是select语句的时候,才有本步)
6.释放资源(使用完资源后一定要关闭资源,Java和数据库之间属于进程间的通信,开启之后一定要记得关闭)
六、添加依赖
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
</dependencies>
七、IDEA编写JDBC连接MySQL
第一种注册驱动
package com.wx;
import com.mysql.jdbc.Driver;
import java.sql.*;
public class Text01 {
public static void main(String[] args) throws SQLException {
//1、注册驱动
//创建驱动对象
Driver driver = new Driver();
DriverManager.registerDriver(driver);//获取到了类型
//2、获取连接Mysql
//getConnection(String url, String user, String password)
//URL -> jdbc:subprotocol:subname
// jdbc:mysql://192.168.253.80:3306/bigdata22?useSSL=false
// jdbc-> 协议
// mysql -> 数据库名称
// 将SSL认证关闭
//
String url ="jdbc:mysql://192.168.40.100:3306/bigdata22?useSSL=false";
String user = "root";
String password="123456";
//数据库的连接对象
Connection con = DriverManager.getConnection(url, user, password);
//3、获取执行SQL语句的·对象
Statement statement = con.createStatement();
//4、执行SQL
String sql ="select * from dept";
ResultSet resultSet = statement.executeQuery(sql);
System.out.println(resultSet);
//5、处理结果集
//resultSet.next 当前光标是在数据集之外,如果执行一次next指针对应有数据,那么返回True,否则返回False
while(resultSet.next()){
//获取列的下标是从1开始的
//获取第一列
String string = resultSet.getString(1);
String string1 = resultSet.getString(2);
//获取loc列,名称不区分大小写
String loc = resultSet.getString("loc");
//System.out.println(loc);
System.out.println(String.format("string:%s \t string1:%s \t loc:%s",string,string1,loc));
}
//6、关闭连接
statement.close();
con.close();
}
}
第二中注册驱动:通过反射
package test02;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class Test02 {
public static void main(String[] args) throws Exception {
/**
*
* 注册驱动的另一种方式(最常用的方式)
* 1、注册驱动(告诉Java程序,即将连接的是哪个品牌的数据库)
* DriverManager.registerDriver(new com.mysql.jdbc.Driver());
* 注册驱动的第二种写法:
* 但是今后我们实际开发的时候,驱动包可能不太一样,今天我们连接mysql可能后天我们连接redis,所以这里的类不是一定的
* 将来我们开发好一个程序后,这里的参数是不允许随意改动的,更希望传一个字符串,方便我们后期做配置文件传参
* 通过反射可以获取一个字节码文件对象中的功能
*/
Class.forName("com.mysql.jdbc.Driver");
String url ="jdbc:mysql://192.168.40.100:3306/bigdata22?useSSL=false";
String user ="root";
String password = "123456";
Connection connection = DriverManager.getConnection(url, user, password);
Statement statement = connection.createStatement();
String sql="select * from dept ";
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()){
String string = resultSet.getString(1);
System.out.println(string);
}
statement.close();
connection.close();
}
}
八、处理结果集
1、如果是查询语句,就调用executeQuery()返回一个结果集
String sql ="select * from dept";
ResultSet resultSet = statement.executeQuery(sql);
System.out.println(resultSet);
//处理结果集
//resultSet.next 当前光标是在数据集之外,如果执行一次next指针对应有数据,那么返回True,否则返回False
while(resultSet.next()){
//获取列的下标是从1开始的
//获取第一列
String string = resultSet.getString(1);
String string1 = resultSet.getString(2);
//获取loc列,名称不区分大小写
String loc = resultSet.getString("loc");
System.out.println(String.format("string:%s \t string1:%s \t loc:%s",string,string1,loc));
2、如果是更新操作 insert into delet from...........返回的是受影响的行数,可以判断是否插入成功
String sql ="delete from emp where ename in (select ena from ((select ename as ena from emp where sal>(select avg(sal) as avg from emp)) as a))";
int rows = statement.executeUpdate(sql);
System.out.println(rows);
//5、处理结果
if(rows>0){
System.out.println("删除成功。。。");
}else{
System.out.println("删除失败。。。");
}
九、java中的配置文件
Java中的配置文件名称一般都以“.properties”和“.xml”进行结尾,这些配置文件的结构都和Java的HashMap结构是一样的,其作用是通过修改配置文件来实现代码中的参数的更改,从而实现灵活变更参数。
package com.wx;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;
/**
* 需求:为了防止生产环境和开发环境所连接的Mysql数据库不一致导致需要修改代码,
* 所以可以将连接信息放在配置文件中
*
* 注意在项目中,一般配置文件需要放在Resources目录中
*/
public class Test03Properties {
public static void main(String[] args) throws IOException, ClassNotFoundException, SQLException {
在配置文件中,文件以.properties结尾,
// 并且文件中格式为 key=value
//load方法其实就是逐行读取properties配置文件,
// 分隔成两个字符串key和value,将他们放进Properties对象中。
//后面如果需要用到这些值,直接调用Properties对象就可以了。
Properties properties=new Properties();
properties.load(new FileReader("D:\\Project\\bigdatda22\\mvn_project\\jdbc_mysql\\src\\main\\resources\\jdbc.properties"));
//1、注册驱动
//mysql驱动会改,这种方式,只需要修改配置文件就可以了
String driver = properties.getProperty("driver");
通过反射可以获取一个字节码文件对象中的功能
Class.forName(driver);
//2、获取连接
String url = properties.getProperty("url");//读取配置文件中的属性
String user = properties.getProperty("user");
String password = properties.getProperty("password");
Connection connection = DriverManager.getConnection(url, user, password);
//获取执行对象
Statement statement = connection.createStatement();
//执行sql
String sql="select * from dept";
ResultSet resultSet = statement.executeQuery(sql);
//处理结果
while (resultSet.next()){
//光标指向的是行数据
//取数据的时候,是一列一列取的
//getString()方法的特点是,不管数据库中字段数据是什么类型的,取出来都是String类型
//这里方法中的参数是int类型数据,1,2,3等代表的是第几列
//String empno = resultSet.getString(1); //JDBC中所有的下标都是从1开始
String string = resultSet.getString(1);
String string1 = resultSet.getString(2);
System.out.println(string+"\t"+string1);//通过空格拼接
}
//关闭连接
//先关闭里面的
statement.close();
connection.close();
}
}
配置文件
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://192.168.40.100:3306/bigdata22?useSSL=false
user=root
password=123456
十、用户登录例子(不安全)
package com.wx;
import java.sql.*;
public class Test04UserLogin {
static Connection con;
//在静态代码块中,创建连接
//在类加载的时候就进行初始化
static {
try {
//1、注册驱动
通过反射可以获取一个字节码文件对象中的功能
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
//2、获取连接
String url ="jdbc:mysql://192.168.40.100:3306/bigdata22?useSSL=false";
String user = "root";
String password="123456";
//数据库的连接对象
try {
con = DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public static boolean login(String id ,String password) throws SQLException {
//3、获取执行的对象
Statement statement = con.createStatement();
//4、执行sql
//字符串拼接
//select * from user_info WHERE user_id = " id " and pw = md5(" password");
//select * from user_info WHERE user_id = ' id ' and pw = md5(' password')
String sql = "select * from user_info WHERE user_id = '"+ id+" ' and pw = md5('" + password + "')";
ResultSet resultSet = statement.executeQuery(sql);
//5、处理结果
if(resultSet.next()){
return true;
}else {
return false;
}
}
public static void main(String[] args) throws SQLException {
//boolean login = login("1001", "123456");
//虽然加密了,任然可以登录成功,语法漏洞
boolean login = login("1001", "')or('1'='1");
if(login){
System.out.println("登录成功");
}else{
System.out.println("登录失败");
}
}
}
十一、用户登录(安全)预编译
package com.wx;
import java.sql.*;
public class Test05SafeLogin02 {
static Connection con;
//在静态代码块中,创建连接
//在类加载的时候就进行初始化
static {
try {
//1、注册驱动
通过反射可以获取一个字节码文件对象中的功能
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
//2、获取连接
String url ="jdbc:mysql://192.168.40.100:3306/bigdata22?useSSL=false";
String user = "root";
String password="123456";
//数据库的连接对象
try {
con = DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public static boolean login(String id ,String password) throws SQLException {
//3、获取执行的对象
// Statement statement = con.createStatement();
//4、执行sql
//字符串拼接
//String sql = "select * from user_info WHERE user_id = '"+ id+" ' and pw = md5('" + password + "')";
//ResultSet resultSet = statement.executeQuery(sql);
/**
* 解决sql注入的问题
只要用户提供的信息不参与sql语句编译过程就好了,这样的话问题就得到解决
java中提供了另外一个接口给我们使用java.sql.PreparedStatement
这个接口继承自原本Statement接口
表示预编译的SQL语句的对象。
SQL语句已预编译并存储在PreparedStatement对象中。 然后可以使用该对象多次有效地执行此语句。
综上所述:大部分情况下,使用PreparedStatement,有些情况下使用statement,如果将来需要手动输入升序或者降序的时候
*/
// 预编译模式,在SQL执行之前将SQL编译成功
//在本地直接生成一个编译过程,再把结果发给mysql编译器
//这里问号相当于一个占位符,将来需要传值的
String sql = "select * from user_info WHERE user_id = ? and pw = md5(?)";
//二、查询数据
PreparedStatement preparedStatement = con.prepareStatement(sql);
//1表示第一个占位
// 给占位符 ? 进行传值,(第一个问号下标是1,第二个问号下标是2,依次类推)
preparedStatement.setString(1,id);
preparedStatement.setString(2,password);
//执行sql
ResultSet resultSet = preparedStatement.executeQuery();
if(resultSet.next()){
preparedStatement.close();
return true;
}else {
preparedStatement.close();
return false;
}
}
public static void main(String[] args) throws SQLException {
boolean login = login("1001", "123456");
//虽然加密了,任然可以登录成功,语法漏洞
//使用preparedStatement就不能成功了
// boolean login = login("1001", "')or('1'='1");
if(login){
System.out.println("登录成功");
}else{
System.out.println("登录失败");
}
}
}
十二、向数据库表中插入一行数据
用preparedStatemen.setString()传值
package com.wx;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Test07Insert {
static Connection con;
//在静态代码块中,创建连接
//在类加载的时候就进行初始化
static {
try {
//1、注册驱动
通过反射可以获取一个字节码文件对象中的功能
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
//2、获取连接
//&useUnicode=true&characterEncoding=UTF-8
String url ="jdbc:mysql://192.168.40.100:3306/bigdata22?useSSL=false&useUnicode=true&characterEncoding=UTF-8";
String user = "root";
String password="123456";
//数据库的连接对象
try {
con = DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws SQLException {
String sql = "insert into foods_info values (?,?,?,?,?)";
//¥1590.00,4000+人付款,【情人节礼物】SK-II神仙水精华液护肤精华水补水紧致抗皱skllsk2,skii官方旗舰店,江苏 苏州
PreparedStatement preparedStatement = con.prepareStatement(sql);
preparedStatement.setString(1,"¥1590.00");
preparedStatement.setString(2,"4000+人付款");
preparedStatement.setString(3,"【情人节礼物】SK-II神仙水精华液护肤精华水补水紧致抗皱skllsk2");
preparedStatement.setString(4,"skii官方旗舰店");
preparedStatement.setString(5,"江苏 苏州");
int rows = preparedStatement.executeUpdate();
if(rows>0){
System.out.println("插入成功");
}else {
System.out.println("插入失败");
}
}
}
十三、读取文件,将文件的多行数据插入到数据库表中
可能会存在编码格式问题,解决办法:在连接的url后面加上
&useUnicode=true&characterEncoding=UTF-8
用preparedStatemen
package com.wx;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* 该方式为在while循环中,每读取一行数据,之后将数据包装并连接Mysql,将SQL发送至Mysql进行执行,再获取结果。
* 这样整个过程相对较慢。和MySQL握手的时间较长,所以优化的方向为:减少访问次数
*
*/
public class Test08Insert02 {
static Connection con;
//在静态代码块中,创建连接
//在类加载的时候就进行初始化
static {
try {
//1、注册驱动
通过反射可以获取一个字节码文件对象中的功能
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
//2、获取连接
//&useUnicode=true&characterEncoding=UTF-8
String url ="jdbc:mysql://192.168.40.100:3306/bigdata22?useSSL=false&useUnicode=true&characterEncoding=UTF-8";
String user = "root";
String password="123456";
//数据库的连接对象
try {
con = DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws Exception {
long satrtTime = System.currentTimeMillis();
//1、IO流读取数据
//读取一行
BufferedReader bufferedReader = new BufferedReader(new FileReader("D:\\Project\\bigdatda22\\mvn_project\\jdbc_mysql\\data\\foods.csv"));
String sql = "insert into foods_info values (?,?,?,?,?)";
//¥1590.00,4000+人付款,【情人节礼物】SK-II神仙水精华液护肤精华水补水紧致抗皱skllsk2,skii官方旗舰店,江苏 苏州
PreparedStatement preparedStatement = con.prepareStatement(sql);
String line =null;
int count =0;
while ((line = bufferedReader.readLine())!=null){
//2、对数据进行切分
String[] split = line.split(",");
// 3、执行sql, 将数据填充到数据库
//先传值
preparedStatement.setString(1,split[0]);
preparedStatement.setString(2,split[1]);
preparedStatement.setString(3,split[2]);
preparedStatement.setString(4,split[3]);
preparedStatement.setString(5,split[4]);
// 每填充一行数据,就可以到数据库中执行
//4、再执行
int rows = preparedStatement.executeUpdate();
count +=1;
if(rows>0){
System.out.println(count+"行插入成功");
}else {
System.out.println("插入失败");
}
}
long endTime = System.currentTimeMillis();
System.out.println((endTime-satrtTime)/100);
//5、关闭
preparedStatement.close();
con.close();
}
}
十四、优化:一次插入多行数据
在SQL中 Values后可以跟多行数据 可以在代码中对SQL语句进行拼接 , 拼接就不能用预编译的模式。用statement。
package com.wx;
import java.io.BufferedReader;
import java.io.FileReader;
import java.sql.*;
/**
*
* 优化思路:
* 在SQL中 Values后可以跟多行数据 可以在代码中对SQL语句进行拼接
* 拼接就不能用预编译的模式
*
* 将数据拼接五行行以后再去提交执行。
*/
public class Test09Insert03 {
static Connection con;
//在静态代码块中,创建连接
//在类加载的时候就进行初始化
static {
try {
//1、注册驱动
通过反射可以获取一个字节码文件对象中的功能
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
//2、获取连接
//&useUnicode=true&characterEncoding=UTF-8
String url ="jdbc:mysql://192.168.40.100:3306/bigdata22?useSSL=false&useUnicode=true&characterEncoding=UTF-8";
String user = "root";
String password="123456";
//数据库的连接对象
try {
con = DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws Exception {
//1、IO流读取数据 创建读取对象 字符缓冲流
BufferedReader bufferedReader = new BufferedReader(new FileReader("D:\\Project\\bigdatda22\\mvn_project\\jdbc_mysql\\data\\foods.csv"));
//获取执行对象
Statement statement = con.createStatement();
String line =null;
int count =0;
long satrtTime = System.currentTimeMillis();
while ((line = bufferedReader.readLine())!=null){
//2、对数据进行切分
String[] split = line.split(",");
// 3、执行sql, 将数据填充到数据库
String sql = "insert into foods_info values ";
String oneline = String.format("('%s','%s','%s','%s','%s'),", split[0], split[1], split[2], split[3], split[4]);
//sql拼接
sql+=oneline;
//格式
//sql1 = insert into foods_info values (split[0], split[1], split[2], split[3], split[4]), (split[0], split[1], split[2], split[3], split[4]),最后有个逗号,需要
//count++;不能用
count+=1;
if(count>=5){
int rows = statement.executeUpdate(sql.substring(0,sql.length()-1));
//截取字符串获取从0开始,到倒数第二个字符的字符串,就能把逗号去掉
//给下次的sql初始化一下
sql = "insert into foods_info values ";
if(rows>0){
System.out.println(count + "行插入成功");
}else {
System.out.println("插入失败");
}
count = 0;
}
}
//用时
long endTime = System.currentTimeMillis();
System.out.println((endTime-satrtTime)/10);
//5、关闭
statement.close();
con.close();
}
}