JDBC是什么?
jdbc是一个由sun公司(Oracle)提出的规范(一套接口),jdbc指的就是java语言连接数据库
jdbc就是一套面向所有数据库厂家的接口
每一个数据库厂家都希望可以通过java语言连接到自己开发的数据库,
这个时候,厂家肯定要写一套程序,java语言连接数据库的具体实现,这个实现类必须要实现JDBC接口
例如:java语言连接 Mysql
mysql的厂家就必须要实现jdbc这个接口
JDBC的驱动类型
JDBC的用途
保证mysql服务是开启的
将java包导入到工程lib下,并且添加到类路径下(保证版本对应)
注册驱动,使用Class类下的一个静态方法forName,使得类加载
获取数据库连接 DriverManager类提供了getConnection方法 (需要传入数据源信息)
获取数据库操作对象 createStatement方法
编写sql语句
按照sql语句的类别调用不同方法,获取到返回的结果
关闭数据库资源(放在finally语句块中)
xxxxxxxxxx
1171package com.os467.test;
2
3import java.sql.*;
4
5/**
6 * JDBC编程六步:
7 * 1.注册驱动
8 * 2.获取数据库连接
9 * 3.获取数据库操作对象
10 * 4.执行sql
11 * 5.返回记录条数/获取结果集对象
12 * 6.关闭资源
13 */
14
15public class JdbcTest01 {
16
17 public static void main(String[] args) {
18
19 //使三个实例作为成员变量存在在类中,使得finally语句块中可以读取到
20 Connection connection = null;
21
22 Statement statement = null;
23
24 ResultSet resultSet = null;
25
26 try{
27
28 //1.注册驱动
29 Class.forName("com.mysql.cj.jdbc.Driver");
30
31 //2.获取数据库链接
32 /**
33 * String url 链接数据库的地址
34 * String user 数据库的用户名 root
35 * String password 数据库密码 root
36 * jdbc:mysql:// 协议
37 * localhost 本地的ip地址
38 * 3306 默认端口号
39 * os467test 需要使用的数据库
40 * ?serverTimezone=GMT 设置时区
41 */
42
43 String url = "jdbc:mysql://localhost:3306/os467test?serverTimezone=GMT";
44
45 String user = "root";
46
47 String password = "root";
48
49 connection = DriverManager.getConnection(url, user, password);
50
51 System.out.println(connection);
52
53 //3.获取数据库操作对象
54 statement = connection.createStatement();
55
56 //4.编写sql语句,执行sql
57 String sql = "select * from emp";
58
59 //5.执行sql,获取返回的结果集对象,遍历结果集
60 resultSet = statement.executeQuery(sql);
61
62 while(resultSet.next()){
63
64 //取出结果集中的数据
65 int empno = resultSet.getInt("EMPNO");
66
67 String ename = resultSet.getString("ENAME");
68
69 System.out.println("员工的编号为"+empno+" 员工的姓名为"+ename);
70
71 }
72
73
74 }catch (Exception e){
75
76 e.printStackTrace();
77
78 }finally {
79
80 //6.关闭数据库资源,先进行非空校验,对close()可能发生的异常进行处理
81 if (resultSet != null){
82
83 try {
84 resultSet.close();
85 } catch (SQLException throwables) {
86 throwables.printStackTrace();
87 }
88
89 }
90
91 if (statement != null){
92
93 try {
94 statement.close();
95 } catch (SQLException throwables) {
96 throwables.printStackTrace();
97 }
98
99 }
100
101 if (connection != null){
102
103 try {
104 connection.close();
105 } catch (SQLException throwables) {
106 throwables.printStackTrace();
107 }
108
109 }
110
111 }
112
113 }
114
115
116}
117
注意:在为字符集添加中文数据时,在url后面用&拼接characterEncoding=utf-8来设置字符集
并且数据库校对中每个字段的字符集也要设置为utf-8
xxxxxxxxxx
841package com.os467.test;
2
3import javax.swing.*;
4import java.sql.*;
5
6/**
7 * 往学生表中添加数据
8 */
9public class JdbcTest03 {
10
11 public static void main(String[] args) {
12
13 Connection connection = null;
14
15 Statement statement = null;
16
17 try {
18
19 //加载jdbc驱动
20 Class.forName("com.mysql.cj.jdbc.Driver");
21
22 String url = "jdbc:mysql://localhost:3306/os467test?serverTimezone=GMT&characterEncoding=utf-8";
23
24 String user = "root";
25
26 String password = "root";
27
28 //链接数据库
29 connection = DriverManager.getConnection(url, user, password);
30
31 //获取操作对象
32 statement = connection.createStatement();
33
34 String sql = "insert into tb_student(name,age,hobby)" +
35 "value('Tom',18,'打篮球')";
36
37 int num = statement.executeUpdate(sql);
38
39 if (num != 0){
40
41 System.out.println("添加成功");
42 }else{
43
44 System.out.println("添加失败");
45
46 }
47
48 }catch (Exception e){
49
50 e.printStackTrace();
51
52 }finally {
53
54 //关闭数据库资源,避免占用系统资源
55 if (statement != null){
56
57 try {
58 statement.close();
59 } catch (SQLException throwables) {
60 throwables.printStackTrace();
61 }
62
63 }
64
65 if (connection != null){
66
67 try {
68 connection.close();
69 } catch (SQLException throwables) {
70 throwables.printStackTrace();
71 }
72
73 }
74
75
76
77 }
78
79
80 }
81
82
83}
84
//模拟用户登入
xxxxxxxxxx
981package com.os467.test;
2
3import java.sql.*;
4import java.util.Scanner;
5
6public class UserJDBCTest02 {
7
8 public static void main(String[] args) {
9
10 //创建控制台打印对象
11 Scanner scanner = new Scanner(System.in);
12
13 System.out.println("请输入用户名:");
14
15 String username = scanner.next();
16
17 System.out.println("请输入密码:");
18
19 String password = scanner.next();
20
21
22 Connection connection = null;
23
24 Statement statement = null;
25
26 ResultSet resultSet = null;
27
28 try{
29
30 //注册驱动
31 Class.forName("com.mysql.cj.jdbc.Driver");
32
33 String url = "jdbc:mysql://localhost:3306/web_test?serverTimezone=GMT&characterEncoding=utf-8";
34
35 //获取数据库对象
36 connection = DriverManager.getConnection(url,"root","root");
37
38 //获取数据库操作对象
39 statement = connection.createStatement();
40
41 resultSet = statement.executeQuery("select * from tb_user where username = '" + username + "' and password = '" + password + "'");
42
43 //判断结果集是否为空和集合中是否有元素
44 if(resultSet != null && resultSet.next()){
45
46 System.out.println("登入成功");
47
48 }else{
49
50 System.out.println("登入失败");
51
52 }
53
54 }catch (Exception e){
55
56 e.printStackTrace();
57
58 }finally {
59
60 if (resultSet != null){
61
62 try {
63 resultSet.close();
64 } catch (SQLException throwables) {
65 throwables.printStackTrace();
66 }
67
68 }
69
70 //关闭数据库资源
71 if (statement != null){
72
73 try {
74 statement.close();
75 } catch (SQLException throwables) {
76 throwables.printStackTrace();
77 }
78
79 }
80
81 if (connection != null){
82
83 try {
84 connection.close();
85 } catch (SQLException throwables) {
86 throwables.printStackTrace();
87 }
88
89 }
90
91 }
92
93
94
95 }
96
97}
98
数据库中创建的每一张表 在java中都有一个实体与之对应
table中的字段对应的是实体beans中的属性
tb_user User
uid uid
username username
password password
通过jdbc来读取数据,这些数据也是以对象的形式被封装在结果集容器中ResultSet
resultSet !=null && resultSet.next()
第一个条件保证容器对象不为空,判断容器中是否有元素
我们会将读取的数据封装成对象,然后将对象装进集合中(ArrayList/HashMap)
后面学习了前端之后,我们会将集合对象传到前端,在前端取出集合中的数据,渲染数据!
java事务
实际上,一个Java应用系统,如果要操作数据库,则通过JDBC来实现的。增加、修改、删除都是通过相应方法间接来实现的,事务的控制也相应转移到java程序代码中。因此,数据库操作的事务习惯上就称为Java事务。
通俗的理解,事务是一组原子操作单元,从数据库角度说,就是一组SQL指令,要么全部执行成功,若因为某个原因其中一条指令执行有错误,则撤销先前执行过的所有指令。更简单的说就是:要么全部执行成功,要么撤销不执行。
事务的原子性:表示事务执行过程中的任何失败都将导致事务所作的任何修改失败
事务的一致性:表示当事务执行失败时,所有被该事务影响的数据都应该恢复到事务执行前的状态
事务的隔离性:表示在事务执行过程中对数据的修改,在事务提交之前对其他事务不可见
事务的持久性:表示已提交的数据在事务执行失败时,数据的状态都应该正确
案例:
银行存钱
银行取钱
转账方法 A B
假设有一个转账的场景:A账户转账给B账户,这个时候我们需要在A账户上扣钱,在B账户上加钱
所以我们需要去写两条sql来完成这样的需求,但是我们要开启事务的支持,因为这两条sql是在一条事务线上的,所以要么同时执行成功,要么同时失败,要满足事务的原子性和一致性。
事务案例代码:
jdbc默认状态下是自动提交的
connection.setAutoCommit();
然后在sql都执行成功的情况下我们要进行一个事务提交的操作connection.commit();
connection.rollback()
是一个回滚的方法,是为了让事务回到执行之前的状态xxxxxxxxxx
861/**
2 * A账户向B账户转账1000
3 *
4 * 模拟一个异常
5 *
6 * 开启对事务的支持
7 *
8 * 在jdbc中如何开启对事务的支持
9 *
10 * jdbc默认是关闭事务的,如果想开启事务的话需要 connection.setAutoCommit();
11 */
12public class JdbcDemo02 {
13
14 public static void main(String[] args) {
15
16 Connection connection = null;
17
18 Statement statement = null;
19
20 try{
21
22 Class.forName("com.mysql.cj.jdbc.Driver");
23
24 connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/web_test?serverTimezone=GMT&characterEncoding=utf-8", "root", "root");
25
26 //将自动提交设置为手动提交
27 connection.setAutoCommit(false);
28
29 statement = connection.createStatement();
30
31 //A账户扣钱
32 int num = statement.executeUpdate("update tb_account set balance_A = balance_A - 1000 where id = 1");
33
34 System.out.println(num==1 ? "扣钱成功" : "扣钱失败");
35
36 //模拟一个异常
37 int i = 1 / 0;
38
39 //B账户加钱
40 num = statement.executeUpdate("update tb_account set balance_B = balance_B + 1000 where id = 1");
41
42 System.out.println(num==1?"转账成功":"转账失败");
43
44 //提交事务
45 connection.commit();
46
47 } catch (Exception e) {
48
49 e.printStackTrace();
50
51 }finally{
52
53 if (statement != null){
54
55 try {
56 statement.close();
57 } catch (SQLException throwables) {
58
59 //事务回滚
60 try {
61 connection.rollback();
62 } catch (SQLException e) {
63 e.printStackTrace();
64 }
65
66 throwables.printStackTrace();
67 }
68
69 }
70
71 if (connection != null){
72
73 try {
74 connection.close();
75 } catch (SQLException throwables) {
76 throwables.printStackTrace();
77 }
78
79 }
80
81 }
82
83 }
84
85}
86
sql注入:指的就是通过在sql中加入数据库的关键字,导致最终sql执行的结果是错误的
PreparedStatement 这个对象可以防止sql注入 因为这个对象在执行sql的时候
是分为两个步骤: 1.先预编译sql,先把sql的架子给搭建出来,但是没有赋值,2.给sql中注入具体的数据,执行sql
Statement对象没有预编译的过程,直接就是执行sql
考虑到安全性我们以后不会直接使用Statement
而是使用PreparedStatement
xxxxxxxxxx
151 //获取数据库操作对象并且预编译sql
2 PreparedStatement preparedStatement = connection.prepareStatement("select * from tb_user where username = ? and password = ? ");
3
4 //给占位符?赋值,占位符从1开始
5 preparedStatement.setString(1,"jack001");
6 preparedStatement.setString(2,"123456");
7
8 //执行sql
9 resultSet = preparedStatement.executeQuery();
10
11 if (resultSet != null && resultSet.next()){
12
13 System.out.println("登录成功");
14
15 }
关于数据库的悲观锁和乐观锁(都是跟事务有关的):
乐观锁:假设在多线程场景下,多个线程同时对数据库中的一个表进行操作
如果多个线程会去修改同一条数据,乐观锁的思想就是觉得这种情况不可能发生
乐观锁:乐观锁可以不用去开启事务的支持(采用的是自动提交的策略)
xxxxxxxxxx
11update tb_user set username = 'tom' where id = 1 and version = "影响记录条数只要大于等于1,这个 版本号就会改变"
悲观锁:针对于以上描述的情况,悲观锁思想就会觉得这种情况一定会发生,然后要提前去解决这个问题
悲观锁一定要去开启对事务的支持,采用手动提交的策略来解决问题,行级锁,在sql后面加上 for update
xxxxxxxxxx
11select * from tb_account where id = 1 for update;
当一个线程在对某一条记录进行查询的时候,那么别的线程只能等待
工具类不能实例化对象,构造函数被private修饰
所有的方法都要被static修饰
xxxxxxxxxx
801package com.os467.utils;
2
3import java.sql.*;
4
5/**
6 * 封装工具类的步骤:
7 *
8 * 1.构造方法私有化
9 * 2.所有的方法都得是静态方法
10 *
11 */
12
13public class JdbcUtils {
14
15 //私有化构造方法
16 private JdbcUtils(){
17
18 }
19
20 //注册驱动
21 static {
22
23 try {
24 Class.forName("com.mysql.cj.jdbc.Driver");
25 } catch (ClassNotFoundException e) {
26 e.printStackTrace();
27 }
28
29 }
30
31 /**
32 * 获取数据库链接方法
33 */
34 public static Connection getConnection() throws SQLException{
35
36 return DriverManager.getConnection("jdbc:mysql://localhost:3306" +
37 "/web_test?serverTimezone=GMT&characterEncoding=utf-8",
38 "root", "root");
39
40 }
41
42 /**
43 * 用于关闭资源的方法
44 */
45 public static void getClose(ResultSet resultSet, Statement statement,Connection connection){
46
47 if (resultSet != null){
48
49 try {
50 resultSet.close();
51 } catch (SQLException throwables) {
52 throwables.printStackTrace();
53 }
54
55 }
56
57 if (statement != null){
58
59 try {
60 statement.close();
61 } catch (SQLException throwables) {
62 throwables.printStackTrace();
63 }
64
65 }
66
67 if (connection != null){
68
69 try {
70 connection.close();
71 } catch (SQLException throwables) {
72 throwables.printStackTrace();
73 }
74
75 }
76
77 }
78
79}
80
利用工具类来执行sql
xxxxxxxxxx
571package com.os467.demmo;
2
3import com.os467.utils.JdbcUtils;
4
5import java.sql.Connection;
6import java.sql.PreparedStatement;
7import java.sql.ResultSet;
8import java.sql.SQLException;
9
10public class JdbcDemo03 {
11
12 public static void main(String[] args) {
13
14 PreparedStatement preparedStatement = null;
15
16 ResultSet resultSet =null;
17
18 Connection connection = null;
19
20 try {
21 //获取数据库链接对象
22 connection = JdbcUtils.getConnection();
23
24 //获取数据库操作对象
25 preparedStatement = connection.prepareStatement("select * from tb_user");
26
27 //执行sql
28 resultSet = preparedStatement.executeQuery();
29
30 if (resultSet != null){
31
32 while (resultSet.next()){
33
34 int uid = resultSet.getInt("uid");
35
36 String username = resultSet.getString("username");
37
38 String password = resultSet.getString("password");
39
40 System.out.println(uid+" "+username+" "+password);
41
42 }
43
44 }
45
46 } catch (SQLException throwables) {
47 throwables.printStackTrace();
48 }finally {
49
50 JdbcUtils.getClose(resultSet,preparedStatement,connection);
51
52 }
53
54 }
55
56}
57