赞
踩
Java DataBase Connectivity(Java语言连接数据库)
JDBC是SUN公司制定的一套接口(interface)。
接口都有调用者和实现者。
面向接口调用、面向接口写实现类,这都属于面向接口编程。
解耦合:降低程序的耦合度,提高程序的扩展力。
多态机制就是非常典型的:面向抽象编程。(不要面向具体编程)
因为每一个数据库产品都有自己独特的实现原理
1.注册驱动(告诉Java程序,即将连接的是哪个品牌的数据库)
2.获取连接(表示JVM的进程和数据库进程之间的通道打开了,这属于进程之间的通信,使用完后记得关闭通道)。
3.获取数据库操作对象(专门执行sql语句的对象)
4.执行SQL语句(DQL,DML…)
5.处理查询结果集 (只有当第四步执行的是select语句的时候,才有本步)
6.释放资源(使用完资源后一定要关闭资源,Java和数据库之间属于进程间的通信,开启之后一定要记得关闭)
6.1 mysql-connector-java的不同版本对比
MySQL Connector / J 5.1 5.1版本支持java5及其以上的版本,支持5.6、5.7、8.0版本的mysql数据库,支持3.0、4.0、4.1、4.2版本的jdbc。在5.1中,Driver的实现类的全路径名是com.mysql.jdbc.Driver。
MySQL Connector / J 8.0 8.0版本支持java8及其以上的版本,支持5.6、5.7、8.0版本的mysql数据库,支持4.2版本的jdbc。在8.0中,Driver的实现类的全路径名是com.mysql.cj.jdbc.Driver。
下图是官网上mysql-connector-java的版本对应的mysql版本和jdk的版本。
6.2 下载驱动jar包 mysql-connector-java
要使用mysql连接器,就要先下载它。如果是一般的项目,那我们需要下载jar包,然后放到项目的lib目录下。如果使用maven构建的项目,我们可以通过maven直接安装。不同的下载方式有不同的操作,常见的有直接官网下载和maven下载(下周讲解maven)。 下载jar包最直接的方式是从官网下载,官网地址是:MySQL :: Download MySQL Connector/J (Archived Versions)。直接点链接进入mysql官网,选择所需的版本和操作系统(要下载jar包就要选:Platform Independent),然后点击download按钮就可以下载了。为java提供的连接器是Connector / J,也就是mysql-connector-java,它分为5.1版本和8.0版本。Connector / J实现了JDBC,为使用java开发的程序提供连接,方便java程序操作数据库。
此处我们使用5.1.49版本,网盘链接也一并贴在这里
2、从maven安装 使用maven安装mysql-connector-java就简单很多,直接打开maven的中央仓库地址,输入mysql-connector-java就可以找到不同版本的依赖。地址:https://mvnrepository.com/artifact/mysql/mysql-connector-java
6.3 IDEA导入jar包
先检查jar包位置:在目录里新建一个文件夹 libs,把jar包复制进去
然后右键选择新建文件夹libs转成library
然后就可以写代码啦!
根据六步编写代码
6.4 JDBC连接mysql 程序编写
这里在数据库中有一个dept表,结构如下:
6.4.1 第一种注册驱动方式
- package com.learn;
-
-
- /*
- 1.注册驱动(告诉Java程序,即将连接的是哪个品牌的数据库)
- 2.获取连接(表示JVM的进程和数据库进程之间的通道打开了,这属于进程之间的通信,使用完后记得关闭通道)。
- 3.获取数据库操作对象(专门执行sql语句的对象)
- 4.执行SQL语句(DQL,DML…)
- 5.处理查询结果集 (只有当第四步执行的是select语句的时候,才有本步)
- 6.释放资源(使用完资源后一定要关闭资源,Java和数据库之间属于进程间的通信,开启之后一定要记得关闭)
- */
-
- import com.mysql.jdbc.Driver;
-
- import java.sql.*;
-
- public class JDBCDemo1 {
- public static void main(String[] args) {
- Connection conn = null;
- Statement state = null;
- //1.注册驱动(告诉Java程序,即将连接的是哪个品牌的数据库)
- //第一种注册驱动的方式
- //jdk本身提供了一个工具类DriverManager来给我们使用
- // 其中有一个方法:registerDriver(Driver driver)用于注册驱动
- //通过观察发现,jdk本身并没有实现Driver接口的类,但mysql驱动中有实现该接口的驱动类。
- try {
- DriverManager.registerDriver(new Driver());
- //2.获取连接(表示JVM的进程和数据库进程之间的通道被打开了,这属于进程之间的通信,使用完后要关闭通道)
- //jdk中提供了一个工具类DriverManager,其中有一个静态的方法,可以让我们调用并且获取与要使用的数据的连接对象
- //static Connection getConnection(String url, String user, String password)
- //尝试建立与给定数据库URL的连接。
- /**
- * url: 统一资源定位系统
- * http/https 通过网络去请求网络上的资源
- * jdbc:mysql 驱动包提供的请求头
- * 请求的地址 指定mysql数据库安装的服务器地址:192.168.169.100
- * 端口号 3306
- * useUnicode=true&characterEncoding=utf8
- *
- * jdbc:mysql://192.168.111.11:3306/bigdata23?useUnicode=true&characterEncoding=utf8&useSSL=false
- */
- // Connection conn = DriverManager.getConnection("jdbc:mysql://192.168.111.11:3306/bigdata23?useUnicode=true&useSSL=false", "root", "123456");
- String url = "jdbc:mysql://192.168.111.11:3306/bigdata23?useUnicode=true&characterEncoding=utf8&useSSL=false";
- String user = "root";
- String password = "123456";
- conn = DriverManager.getConnection(url, user, password);
- //如果连接不上可能导致的问题
- //1、检查虚拟机,服务器是否启动
- //2、检查防火墙是否关闭,指的是虚拟机或者服务器的防火墙
- //3、检查url地址,用户名,密码
- System.out.println("与数据库<" + conn + ">连接成功!!!");
- //3.获取数据库操作对象(专门执行sql语句的对象)
- state = conn.createStatement();
- //4.执行SQL语句(DQL,DML…)
- //DQL
- //ResultSet executeQuery(String sql)
- //执行sql语句,该语句返回查询的结果,只能是查(select)
-
- //DML
- //int executeUpdate(String sql)
- //执行给定的SQL语句,这里可以是增(insert),删(delete),更新(update)
- //该方法的返回值指的是受影响的行数
- String sql1 = "insert into dept values(99,'董事会','安徽合肥')";
- int count = state.executeUpdate(sql1);
- if (count == 1) {
- System.out.println("数据插入成功!");
- } else {
- System.out.println("数据插入失败,请重试。");
- }
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- //6.释放资源(使用完资源后一定要关闭资源,Java和数据库之间属于进程间的通信,开启之后一定要记得关闭)
- if (state != null) {
- try {
- state.close();
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- if (conn != null) {
- try {
- conn.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }
- }
- }
- }
- }
6.4.2 第二种注册驱动方式
使用反射的方式加载驱动类
- package com.learn;
-
- //驱动注册的第二种方式
-
- import com.mysql.jdbc.Driver;
-
- import java.sql.Connection;
- import java.sql.DriverManager;
- import java.sql.SQLException;
- import java.sql.Statement;
-
- public class JDBCDemo2 {
- public static void main(String[] args) throws Exception{
- //使用反射的第三种方式直接获取mysql数据库的驱动类,今后最常用的方式
- Class.forName("com.mysql.jdbc.Driver");
- Connection conn = null;
- Statement state = null;
- //1.注册驱动(告诉Java程序,即将连接的是哪个品牌的数据库)
- //第一种注册驱动的方式
- //jdk本身提供了一个工具类DriverManager来给我们使用
- // 其中有一个方法:registerDriver(Driver driver)用于注册驱动
- //通过观察发现,jdk本身并没有实现Driver接口的类,但mysql驱动中有实现该接口的驱动类。
- try {
- DriverManager.registerDriver(new Driver());
- //2.获取连接(表示JVM的进程和数据库进程之间的通道被打开了,这属于进程之间的通信,使用完后要关闭通道)
- //jdk中提供了一个工具类DriverManager,其中有一个静态的方法,可以让我们调用并且获取与要使用的数据的连接对象
- //static Connection getConnection(String url, String user, String password)
- //尝试建立与给定数据库URL的连接。
- /**
- * url: 统一资源定位系统
- * http/https 通过网络去请求网络上的资源
- * jdbc:mysql 驱动包提供的请求头
- * 请求的地址 指定mysql数据库安装的服务器地址:192.168.169.100
- * 端口号 3306
- * useUnicode=true&characterEncoding=utf8
- *
- * jdbc:mysql://192.168.111.11:3306/bigdata23?useUnicode=true&characterEncoding=utf8&useSSL=false
- */
- // Connection conn = DriverManager.getConnection("jdbc:mysql://192.168.111.11:3306/bigdata23?useUnicode=true&useSSL=false", "root", "123456");
- String url = "jdbc:mysql://192.168.111.11:3306/bigdata23?useUnicode=true&characterEncoding=utf8&useSSL=false";
- String user = "root";
- String password = "123456";
- conn = DriverManager.getConnection(url, user, password);
- //如果连接不上可能导致的问题
- //1、检查虚拟机,服务器是否启动
- //2、检查防火墙是否关闭,指的是虚拟机或者服务器的防火墙
- //3、检查url地址,用户名,密码
- System.out.println("与数据库<" + conn + ">连接成功!!!");
- //3.获取数据库操作对象(专门执行sql语句的对象)
- state = conn.createStatement();
- //4.执行SQL语句(DQL,DML…)
- //DQL
- //ResultSet executeQuery(String sql)
- //执行sql语句,该语句返回查询的结果,只能是查(select)
-
- //DML
- //int executeUpdate(String sql)
- //执行给定的SQL语句,这里可以是增(insert),删(delete),更新(update)
- //该方法的返回值指的是受影响的行数
- // String sql1 = "insert into dept values(98,'保卫科','安徽合肥')";
- // int count = state.executeUpdate(sql1);
- // if (count == 1) {
- // System.out.println("数据插入成功!");
- // } else {
- // System.out.println("数据插入失败,请重试。");
- // }
-
- //修改数据
- // String sql2 = "update dept set loc='安徽淮南' where deptno = 98";
- // int count2 = state.executeUpdate(sql2);
- // if (count2 == 1) {
- // System.out.println("数据修改成功!");
- // } else {
- // System.out.println("数据修改失败,请重试。");
- // }
-
- //删除数据
- String sql3 = "delete from dept where deptno = 98";
- int count3 = state.executeUpdate(sql3);
- if (count3 == 1) {
- System.out.println("数据删除成功!");
- } else {
- System.out.println("数据删除失败,请重试。");
- }
-
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- //6.释放资源(使用完资源后一定要关闭资源,Java和数据库之间属于进程间的通信,开启之后一定要记得关闭)
- if (state != null) {
- try {
- state.close();
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- if (conn != null) {
- try {
- conn.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }
- }
- }
-
- }
- }
//mysql5.7之后警告用户不要直接访问数据库服务器,于是运行时会有红色警告
解决方法:连接数据库时在url中添加参数&useSSL=false
String url = "jdbc:mysql://192.168.111.11:3306/bigdata23?useUnicode=true&characterEncoding=utf8&useSSL=false";
6.4.3 将连接数据库的所有信息配置到配置文件中
为了方便日后修改数据库信息,我们将数据库参数存到配置文件中。
我们另外创建一个配置文件:mysqlinfo.properties
- url = jdbc:mysql://192.168.111.11:3306/bigdata23?useUnicode=true&characterEncoding=utf8&useSSL=false
- username=root
- password=123456
- package com.learn;
-
- import com.mysql.jdbc.Driver;
-
- import java.io.BufferedReader;
- import java.io.FileReader;
- import java.sql.Connection;
- import java.sql.DriverManager;
- import java.sql.Statement;
- import java.util.Properties;
-
- /*
- 通过读取配置文件获取数据库连接信息
- */
- public class JDBCDemo3 {
- public static void main(String[] args) throws Exception{
- //1、加载数据库驱动
- Class.forName("com.mysql.jdbc.Driver");
- //读取配置文件获取url,用户名以及密码
- Properties prop = new Properties();
- prop.load(new BufferedReader(new FileReader("E:\\Project\\IDEAProject\\bigdata23-learn\\bigdata23-jdbc\\src\\main\\java\\com\\learn\\utils\\mysqlinfo.properties")));
- String url = prop.getProperty("url");
- String username = prop.getProperty("username");
- String password = prop.getProperty("password");
- //2、获取数据库连接对象
- Connection conn = DriverManager.getConnection(url, username, password);
-
- //3、获取数据库操作对象
- Statement state = conn.createStatement();
-
- //4、编写sql语句,执行sql
- String sql = "insert into dept values(97,'保洁','安徽淮南')";
-
- int count = state.executeUpdate(sql);
- if (count==1){
- System.out.println("数据插入成功");
- }else {
- System.out.println("数据插入失败");
- }
-
- //6、释放资源
- state.close();
- conn.close();
-
- }
-
- }
使用工具类改进获取连接代码
- package com.learn.utils;
-
- import java.io.BufferedReader;
- import java.io.FileReader;
- import java.sql.Connection;
- import java.sql.DriverManager;
- import java.util.Properties;
-
- public class MysqlTool {
- private MysqlTool(){}
- public static Connection getConnection(){
- Connection conn = null;
- try{
- //1、加载数据库的驱动
- Class.forName("com.mysql.jdbc.Driver");
-
- //读取配置文件获取url,用户名和密码
- Properties prop = new Properties();
- prop.load(new BufferedReader(new FileReader("E:\\Project\\IDEAProject\\bigdata23-learn\\bigdata23-jdbc\\src\\main\\java\\com\\learn\\utils\\mysqlinfo.properties")));
- String url = prop.getProperty("url");
- String username = prop.getProperty("username");
- String password = prop.getProperty("password");
-
- //2、获取数据库的连接对象
- conn = DriverManager.getConnection(url, username, password);
- }catch (Exception e){
- e.printStackTrace();
- }
-
- if (conn!=null){
- System.out.println("与数据库建立连接成功");
- }else {
- System.out.println("建立连接失败,请重试!");
- }
-
-
- return conn;
- }
- }
6.4.4 处理查询结果集
- package com.learn;
-
- import com.learn.utils.MysqlTool;
-
- import java.sql.Connection;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import java.sql.Statement;
-
- public class JDBCDemo4 {
- public static void main(String[] args) {
- Connection conn = null;
- Statement state = null;
- try{
- //获取连接对象
- conn = MysqlTool.getConnection();
-
- //获取数据库操作对象
- state = conn.createStatement();
-
- //查询
- String sql = "select deptno,dname,loc from dept";
- ResultSet rs = state.executeQuery(sql);
- while (rs.next()){
- //第一种方式:通过索引获取列(索引下标从1开始)
- // String deptno = rs.getString(1);
- // String dname = rs.getString(2);
- // String loc = rs.getString(3);
- //第二张方式:通过列名来获取
- //如果查询语句中有别名的列存在,第二种方式查询的时候,使用别名获取这一列
- String deptno = rs.getString("deptno");
- String dname = rs.getString("dname");
- String loc = rs.getString("loc");
- System.out.println("部门编号:"+deptno+",部门名称:"+dname+",地址:"+loc);
- }
-
- }catch (Exception e){
- e.printStackTrace();
- }finally {
- if (state!=null){
- try {
- state.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }if (conn!=null){
- try {
- conn.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
-
- }
- }
登录注册案例
- package com.learn;
-
- import com.learn.utils.MysqlTool;
-
- import java.sql.Connection;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import java.sql.Statement;
- import java.util.Scanner;
- import java.util.UUID;
-
- public class JDBCDemo5 {
- public static void main(String[] args) throws SQLException {
- //创建键盘录入对象
- Scanner sc = new Scanner(System.in);
- System.out.println("====================欢迎来到美联储后台管理系统!=====================");
- System.out.println("请输入您的用户名:");
- String username = sc.nextLine();
- System.out.println("请输入您的密码:");
- String pwd = sc.nextLine();
-
- //查询数据库中的users表,判断该用户是否存在
- //获取数据库的连接对象
- Connection conn = MysqlTool.getConnection();
- //获取数据库操作对象
- Statement state = conn.createStatement();
- //编写sql查询语句
- String sql = "select username,password from users where username='"+username+"'and password='"+pwd+"'";
- //执行sql语句
- ResultSet rs = state.executeQuery(sql);
- boolean flag = rs.next();
- if (flag){
- System.out.println("登陆成功,您的余额为36415481518.25美元,祝您生活愉快!");
- }else {
- System.out.println("登陆失败,是否注册?(Y/N)");
- String s = sc.nextLine();
- if ("Y".equals(s)){
- System.out.println("请输入您的姓名:");
- String name =sc.nextLine();
- System.out.println("请输入您的用户名:");
- String uname =sc.nextLine();
- System.out.println("请输入您的密码:");
- String password =sc.nextLine();
- System.out.println("请确认您的密码:");
- String password2 =sc.nextLine();
- if (password.equals(password2)){
- //开始进行注册(即把数据插入到数据库中)
- //Java中提供一个类用于生成随机id:UUID
- UUID uuid = UUID.randomUUID();
- String id = uuid.toString();
- String sql2 = "insert into users values('"+id+"','"+name+"','"+uname+"','"+password+"')";
- // System.out.println(sql2);
- int count = state.executeUpdate(sql2);
- if (count==1){
- System.out.println("注册成功,系统随机赠送您36415481518.25美元初始资金,祝您生活愉快!");
- }else {
- System.out.println("系统繁忙,请您稍后再试!");
- }
- }
- }else {
- System.out.println("欢迎下次光临。");
- }
- }
-
- // System.out.println(sql);
- conn.close();
-
- }
- }
可以实现简单的注册登录。
6.4.5 解决sql注入问题
SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。
在上面案例中,我们查询登录语句是
String sql = "select username,password from users where username='"+username+"'and password='"+pwd+"'";
此时我们登录,应该是用户名为president,密码为666
然而读者观察以下结果:
我们神奇的发现,输入的密码并不是666,竟然也能登陆成功,这就是SQL注入。
此时我们再将登陆语句拿过来
select username,password from users where username='"+username+"'and password='"+pwd+"'
我们将输入的内容拼接上去
select username,password from users where username='president'and password='123' or '1'
此时语句最后变成了password='123' or '1',而'1'是个字符串,显然恒为true,导致password='123' or '1'也为true,于是就登陆进了系统
我们再换种方式:
同理:
select username,password from users where username='president'and password='123' or '1'='1'
如果我们是先进行sql拼接,然后再对sql整体做编译的话,会将一些拼接的内容作为sql语法关键字进行处理。但是我们实际上输入的字符就是普通的字符串,不应该当作sql语法的编译。 于是java和mysql团队提供了另一种方式获取数据库操作对象。 解决方案:将原来的先拼接再编译sql的步骤换成:先编译再拼接。
//提前编译好sql,将需要传参数的地方使用问号进行处理 PreparedStatement state = conn.prepareStatement("select name,password from users where name=? and password=?"); state.setString(1,username); state.setString(2,pwd);
改进后的代码如下:
- package com.learn;
-
- import com.learn.utils.MysqlTool;
-
- import java.sql.*;
- import java.util.Scanner;
- import java.util.UUID;
-
- public class JDBCDemo5_2 {
- public static void main(String[] args) throws SQLException {
- //创建键盘录入对象
- Scanner sc = new Scanner(System.in);
- System.out.println("====================欢迎来到美联储后台管理系统!=====================");
- System.out.println("请输入您的用户名:");
- String username = sc.nextLine();
- System.out.println("请输入您的密码:");
- String pwd = sc.nextLine();
-
- //查询数据库中的users表,判断该用户是否存在
- //获取数据库的连接对象
- Connection conn = MysqlTool.getConnection();
- //获取数据库操作对象
- // Statement state = conn.createStatement();
- // //编写sql查询语句
- // String sql = "select username,password from users where username='"+username+"'and password='"+pwd+"'";
- //提供了预编译对象进行处理
- //提前编译好sql,将需要传参数的地方使用问号进行处理
- PreparedStatement state = conn.prepareStatement("select name,password from users where name=? and password=?");
- state.setString(1,username);
- state.setString(2,pwd);
- //执行sql语句
- ResultSet rs = state.executeQuery();
- boolean flag = rs.next();
- if (flag){
- System.out.println("登陆成功,您的余额为36415481518.25美元,祝您生活愉快!");
- }else {
- System.out.println("登陆失败,是否注册?(Y/N)");
- String s = sc.nextLine();
- if ("Y".equals(s)){
- System.out.println("请输入您的姓名:");
- String name =sc.nextLine();
- System.out.println("请输入您的用户名:");
- String uname =sc.nextLine();
- System.out.println("请输入您的密码:");
- String password =sc.nextLine();
- System.out.println("请确认您的密码:");
- String password2 =sc.nextLine();
- if (password.equals(password2)){
- //开始进行注册(即把数据插入到数据库中)
- //Java中提供一个类用于生成随机id:UUID
- UUID uuid = UUID.randomUUID();
- String id = uuid.toString();
- String sql2 = "insert into users values('"+id+"','"+name+"','"+uname+"','"+password+"')";
- // System.out.println(sql2);
- int count = state.executeUpdate(sql2);
- if (count==1){
- System.out.println("注册成功,系统随机赠送您36415481518.25美元初始资金,祝您生活愉快!");
- }else {
- System.out.println("系统繁忙,请您稍后再试!");
- }
- }
- }else {
- System.out.println("欢迎下次光临。");
- }
- }
-
- // System.out.println(sql);
- conn.close();
-
- }
- }
测试:
发现已经无法使用原来的漏洞登录了。
JDBC事物机制: 1.JDBC中的事务自动提交的,什么是自动提交? 只要执行任意一条 DML
语句,则自动提交一次。这是JDBC默认的事务行为。 但是在实际的业务中,通常都是N条DML语句共同联合才能完成,必须 保证这些DML语句在同一个事务中同时成功或者同时失败 解决方案:三行重要的代码 conn.setAutoCommit(false);//手动提交事务 conn.commit();//提交事务 conn.rooback;当发生异常时或者程序错误时,进行回滚。
6.4.6 JDBC实现模糊查询
- package com.learn;
-
- import com.learn.utils.MysqlTool;
-
- import java.sql.Connection;
- import java.sql.PreparedStatement;
- import java.sql.ResultSet;
-
- public class JDBCDemo6 {
- public static void main(String[] args) throws Exception {
- //获取数据库连接对象
- Connection conn = MysqlTool.getConnection();
-
- //获取预编译数据库操作对象
- PreparedStatement pps = conn.prepareStatement("select id,name,password from users where name like ?");
-
- pps.setString(1,"川%");
-
- ResultSet resultSet = pps.executeQuery();
- while (resultSet.next()){
- String name = resultSet.getString(1);
- String password = resultSet.getString(2);
- System.out.println(name+"--"+password);
- }
-
- pps.close();
- conn.close();
- }
- }
6.5 悲观锁和乐观锁的概念
事务1–>读取到版本号1.1 事务2—>读取到版本号1.1
其中事务1先修改了,修改之后看了版本号是1.1 ,于是提交修改的数据,将版本号修改为1.2 其中事务2后修改的,修改之后准备提交的时候,发现版本号是1.2 ,和它最初读的版本号不一致。回滚。
悲观锁:事务必须排队执行。数据锁住了,不允许并发。 (行级锁: select后面添加for update ) 乐观锁:支持并发,事务也不需要排队,只不过需要一个版本号。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。