04-连接查询

SQL的四种连接方式

内连接
inner join 或者join

外连接

  1. 左连接 left join 或者 left outer join
  2. 右连接 right join 或者right outer join
  3. 完全外连接 full join 或者 full outer join
-- 创建两个表:
create database testJoin;

-- person 表
-- id、name、cardId
create table person(
	id int,
	name varchar(20),
	cardId int
);
insert into person values(1,'张三',1);
insert into person values(2,'李四',3);
insert into person values(3,'王五',6);

-- card表
-- id、name
create table card(
	id int,
	name varchar(20)
);
insert into card values(1,'饭卡');
insert into card values(2,'建行卡');
insert into card values(3,'农行卡');
insert into card values(4,'工商卡');
insert into card values(5,'邮政卡');
-- 并没有创建外键

image-20211013143118565

image-20211013143051106

-- 1.inner join 查询(内连接)

-- 内联查询,其实就是两张表中的数据,通过某个相同字段,查询出相关记录数据

mysql> select * from person inner join card on person.cardId=card.id;

image-20211013143632427

-- 2.left join(左外连接)

-- 左外连接,会把左边表里面的所有数据取出来,而右边表中的数据,如果有相等的,就显示出来,如果没有,就会补NULL

mysql> select * from person left join card on person.cardId=card.id;

image-20211013144440076

-- 3.right join(右外连接)

-- 右外连接,会把右边表里面的所有数据取出来,而左边表中的数据,如果有相等的,就显示出来,如果没有,就会补NULL

mysql> select * from person right join card on person.cardId=card.id;

image-20211013144724467

-- 4.full join(全外连接)

mysql> select * from person full join card on person.cardId=card.id;
-- mysql不支持full join,使用左连接union右连接实现
mysql> select * from person left join card on person.cardId=card.id
    -> union
    -> select * from person right join card on person.cardId=card.id;

image-20211013145300053

MySQL事务

-- mysql事务
-- 在mysql中,事务其实是一个最小的不可分割的工作单元,事务能够保证一个业务的完整性。
-- 比如在银行转账:
 	a-> -100
 	update user set money=money-100 where name='a';
 	b-> +100
 	update user set money=money+100 where name='b';

-- 实际程序中,如果只有一条语句执行成功,而另一条没有执行成功,就会出现数据前后不一致
-- 多条sql语句,可能会有要么同时成功,要么就同时失败的要求

-- 事务的四大特征(ACID)
A 原子性:事务是最小的单位,不可再分割
C 一致性:事务执行之前和执行之后都必须处于一致性状态,要么同时成功要么同时失败
I 隔离性:事务1 和 事务2 之间是具有隔离性的
D 持久性:事务一旦结束(commit,rollback),就不可以返回

持久性

-- 持久性是指一个事务一旦被提交,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

-- mysql默认是开启事务的(默认自动提交)。

mysql> select @@autocommit;

image-20211013150334392

-- 默认事务开启的作用:当我们去执行一个sql语句的时候,效果会立即体现出来,且不能回滚
-- 事务回滚(rollback):撤销sql语句执行效果

mysql> create database bank;
mysql> create table user(
    -> id int primary key,
    -> name varchar(20),
    -> money int
    -> );
mysql> insert into user values(1,'a',1000)
mysql> rollback;	-- 默认无法回滚,数据会自动提交

image-20211013151055087

-- 关闭mysql的自动提交(commit)

mysql> set autocommit=0;
mysql> select @@autocommit;

image-20211013151936643

mysql> insert into user values(2,'b',1000);
mysql> select * from user;

image-20211013152133771

mysql> rollback;	-- 回滚
mysql> select * from user;

image-20211013152238543

mysql> insert into user values(2,'b',1000);	-- 再次添加数据
mysql> commit;	-- 手动提交数据(持久性)
mysql> rollback;	-- 不可回滚(持久性)
mysql> select * from user;

image-20211013152544254

自动提交 @@autocommit=1;

手动提交 commit;

事务回滚 rollback;

事务给我们提供了一个返回的机会。

使用 begin;start transaction; 都可以帮我们手动开启一个事务

mysql> set autocommit=1;	-- 打开自动提交
mysql> select @@autocommit;

image-20211013155159316

手动开启事务(1) begin;

mysql> begin;
mysql> update user set money=money-100 where name='a';
mysql> update user set money=money+100 where name='b';
mysql> select * from user;

image-20211013155534764

mysql> rollback;
mysql> select * from user;

image-20211013155629200

手动开启事务(2) start transaction;

mysql> start transaction;
mysql> update user set money=money-100 where name='a';
mysql> update user set money=money+100 where name='b';
mysql> select * from user;

image-20211013160040737

mysql> rollback;
mysql> select * from user;

image-20211013160118116

事务开启之后,一旦commit提交,就不能回滚,事务在提交的时候就结束了。

隔离性

-- 隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离
-- 数据库为事务提供了多种隔离级别:
1.read uncommitted;		读未提交的(脏读)
2.read committed;		读已经提交的(不可重复读)
3.repeatable read;		可以重复读(幻读)
4.serializable;			串行化

数据库的隔离级别:

-- 查看mysql默认隔离级别
mysql> select @@global.transaction_isolation;	-- 系统级别
mysql> select @@transaction_isolation;			-- 会话级别
-- 修改mysql隔离级别
mysql> set [ global.transaction_isolation | transaction_isolation ]='隔离级别';
mysql> set  [glogal | session]  transaction isolation level [隔离级别]

image-20211013161723706

1、脏读

如果有事务a和事务b

a事务对数据进行操作,在操作的过程中,事务没有被提交,但是b可以看见a操作的结果

-- 情形模拟
mysql> insert into user values(3,'小明',1000);
mysql> insert into user values(4,'淘宝店',1000);
mysql> select * from user;

image-20211013163435513

-- 打开两个命令行窗口
-- 修改隔离级别
mysql> set session transaction isolation level read uncommitted;
mysql> select @@transaction_isolation;

image-20211014103314460

-- 转账:小明在淘宝店买鞋子:800块钱
-- 小明->成都ATM
-- 淘宝店->广州ATM

mysql> start transaction;
mysql> update user set money=money-800 where name='小明';
mysql> update user set money=money+800 where name='淘宝店';
mysql> select * from user;

image-20211014082756802

-- 给淘宝店打电话,说你去查一下,是不是到账了
-- 淘宝店在广州查账
mysql> select * from user;
-- 发货,晚上消费1800

image-20211014082846988

-- 小明->成都
mysql> rollback;
mysql> select * from user;

image-20211014083007684

-- 淘宝店->结账发现钱不够
mysql> select * from user;

image-20211014083151899

-- 脏读:一个事务读到了另外一个事务没有提交的数据
-- 如果两个不同的对方都在进行操作,如果事务a开启之后,他的数据可以被其他事务读取到,这样就会出现脏读,只要该事务不提交,则所有操作都将回滚
-- 实际开发中是不允许脏读出现的

2、不可重复读

-- 不可重复读(read committed)是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交

-- 打开两个命令行窗口
-- 修改隔离级别为 READ-COMMITTED
mysql> set session transaction isolation level read committed;	-- 会话级别
mysql> select @@transaction_isolation;

image-20211014093302970

-- 小张开启事务:
mysql> start transaction;
mysql> select * from user;
-- 出门上厕所

image-20211014090717347

-- 小王开启事务:
mysql> start transaction;
mysql> insert into user values(5,'c',100);
mysql> commit;
mysql> select * from user;

image-20211014090900091

-- 小张上完厕所回来
mysql> select avg(money) from user;

image-20211014104751280

-- money的平均不是1000,变少了?
-- 不可重复读和脏读的区别,脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据
-- 小张再次核对数据
mysql> select * from user;

image-20211014105649319

3、幻读

-- 打开两个命令行界面
-- 修改隔离级别为 repeatable read

mysql> set global transaction isolation level repeatable read;	-- 系统级别
mysql> select @@global.transaction_isolation;
mysql> select @@transaction_isolation;

image-20211014105924096

-- 小明开启事务:
mysql> start transaction;
mysql> select * from user;

image-20211014101826306

-- 小红开启事务:
mysql> start transaction;
mysql> insert into user values(6,'d',1000);
mysql> commit;
mysql> select * from user;

image-20211014101811466

-- 小明添加数据
mysql> insert into user values(6,'d',1000);
1062 - Duplicate entry '6' for key 'user.PRIMARY'	-- 失败
-- 查看列表
mysql> select * from user;

image-20211014102008344

这种现象就叫幻读

事务a和事务b同时操作同一张表,事务a提交数据,无法被事务b读到,也就造成了幻读。

-- 小明结束事务
mysql> commit;
-- 再次查看列表
mysql> select * from user;

image-20211014110227856

4、串行化

-- 打开两个命令行窗口
-- 修改隔离级别为串行化
mysql> set session transaction isolation level serializable;
mysql> select @@transaction_isolation;
mysql> select * from user;

image-20211014132238619

-- 小明开启事务
mysql> start transaction;
-- 小红开启事务
mysql> start transaction;
-- 小明插入数据
mysql> insert into user values(7,'张三',1000);
mysql> commit;
mysql> select * from user;

image-20211014132301918

-- 小红查看列表
mysql> select * from user;

image-20211014132325208

-- 小明再次开启事务
mysql> start transaction;
mysql> insert into user values(8,'李四',1000);
1205 - Lock wait timeout exceeded; try restarting transaction
-- sql语句被卡住了?
-- 当user表被另外一个事务操作的时候,其他事务里面的写操作,是不可以进行的
-- 进入排队状态(串行化),直到小红那边的事务结束之后,小明的这个写操作才会执行。

-- 小红结束事务
mysql> commit;
-- 小明继续插入数据
mysql> insert into user values(8,'李四',1000);
mysql> commit;
mysql> select * from user;

image-20211014132941207

-- 总结:
-- 串行化的问题是,性能特差!!
-- 性能排行:
READ-UNCOMMITTED > READ-COMMITTED > REPEATABLE-READ > SERIALIZABLE
-- 隔离级别越高,性能越差
-- mysql 默认隔离级别为 REPEATABLE-READ

JDBC

SUN公司为了简化开发人员的操作,提供了一个Java操作数据库的规范,简称JDBC (Java Database Connectivity), 是一种用于执行SQL语句的Java API,即Java数据库编程接口。

下载数据库驱动包mysql-connector-java-8.0.21.jar,与电脑上的数据库版本相对应。

image-20211015091159192

第一个JDBC程序

1、创建测试数据库

mysql> create database jdbcStudy character set utf8 collate utf8_general_ci;
mysql> use jdbcStudy;
mysql> create table users(
    -> id int primary key,
    -> name varchar(40),
    -> password varchar(40),
    -> email varchar(60),
    -> birthday DATE
    -> );
mysql> insert into users values(1,'zhansan','123456','zhangsan@sina.com','1980-12-04'),(2,'lisi','123456','lisi@sina.com','1981-12-04'),(3,'wangwu','123456','wangwu@sina.com','1979-12-04');
mysql> select * from users;

image-20211015093604574

2、在IDEA创建一个普通项目,导入数据库驱动

image-20211015093945005

image-20211015094409571

image-20211015094543052

导入完成。

3、编写测试代码

package com.wang.lesson01;

import java.sql.*;

//我的第一个JDBC程序
public class JdbcFirstDemo {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //1.加载驱动
        Class.forName("com.mysql.cj.jdbc.Driver");  //固定写法
        //2.用户信息和url
        //userUnicode=true     -- 支持中文编码
        // &characterEncoding=utf8  -- 设置中文字符集utf8
        // &useSSL=true          -- 使用安全连接
        //执行后时区问题报错 差了8个小时  解决办法,在url后面加上 serverTimezone=GMT%2B8(即GMT+8) 或是 serverTimezone=Hongkong
        String url = "jdbc:mysql://localhost:3306/jdbcStudy?userUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=Hongkong";
        String username = "root";
        String password = "201314";

        //3.连接成功,数据库对象  Connection 代表数据库
        Connection connection = DriverManager.getConnection(url, username, password);

        //4.执行SQL的对象
        Statement statement = connection.createStatement();

        //5.执行SQL的对象去执行SQL,可能存在结果,查看返回结果
        String sql = "select * from users";
        ResultSet resultSet = statement.executeQuery(sql);  //返回的结果集
        //resultSet结果集中封装了我们全部的查询出来的结果
        while (resultSet.next()) {
            System.out.println("id=" + resultSet.getObject("id"));
            System.out.println("name=" + resultSet.getObject("name"));
            System.out.println("password=" + resultSet.getObject("password"));
            System.out.println("email=" + resultSet.getObject("email"));
            System.out.println("birthday=" + resultSet.getObject("birthday"));
            System.out.println("======================================================");
        }

        //6.释放连接
        resultSet.close();
        statement.close();
        connection.close();

    }
}

image-20211015102919256

总结:

DriverManager

// DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Class.forName("com.mysql.cj.jdbc.Driver");  //固定写法,加载驱动

 Connection connection = DriverManager.getConnection(url, username, password);
// connection 代表数据库
connection.commit();	// 事务提交
connection.rollback();	// 事务回滚
connection.setAutoCommit(false);	// 数据库设置自动提交

URL

String url = "jdbc:mysql://localhost:3306/jdbcStudy?userUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=Hongkong";

//协议://主机地址:端口号/

//mysql 默认端口号 3306
//jdbc:mysql://localhost:3306/数据库名?参数1&参数2&参数3&

//oracle 默认端口号 1521
//jdbc:oracle:thin:@localhost:1521:sid

Statement执行SQL的对象 PrepareStatement

String sql = "select * from users";	//编写SQL

statement.executeQuery();   //查询操作返回ResultSet
statement.execute();    //执行任何SQL
statement.executeUpdate();  //更新、插入、删除。都是用这个,返回一个受影响的行数

ResultSet查询的结果集:封装了所有的查询结果

获得指定的数据类型

resultSet.getString();  //在不知道列类型的时候使用
//知道列的类型就使用指定的类型
resultSet.getInt();
resultSet.getFloat();
resultSet.getDate();
resultSet.getObject();
...
    
resultSet.beforeFirst();    //移动到最前面
resultSet.afterLast();  //移动到最后面
resultSet.next();   //移动到下一个数据
resultSet.previous();   //移动到前一行
resultSet.absolute(row);    //移动到指定行

释放资源

resultSet.close();
statement.close();
connection.close();		//耗资源,用完关掉!

statement对象

JDBC中的statement对象用于向数据库发生SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可

Statement对象的executeUpdate方法,用于向数据库发送增、删、改的sql语句,executeUpdate执行完后,将会返回一个整数(即增删改语句导致了数据库几行数据发生了改变)。

Statement.executeQuery方法用于向数据库发送查询语句,executeQuery方法返回代表查询结果的ResultSet对象。

CRUD操作-create

使用execute Update(String sql)方法完成数据添加操作,示例操作:

		Statement st = connection.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 = connection.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 = connection.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 = connection.createStatement();
        String sql = "select * from user where id=1";
        int num = st.executeQuery(sql);
        if(num>0){
            //根据获取的数据类型,分别调用rs的相应方法映射到java对象中
        }

封装连接代码

在src目录下新建file->db.properties,添加如下代码:

image-20211015141104335

driver=com.mysql.cj.jdbc.Driver 
url = jdbc:mysql://localhost:3306/jdbcStudy?userUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT%2B8
username = root
password = 201314

新建工具类utils,写入封装代码:

image-20211015141734582

package com.wang.lesson02.utils;

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class JdbcUtils {
    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);

            String dirver = properties.getProperty("driver");
            url = properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");

            //驱动只用加载一次
            Class.forName(dirver);

        } catch (IOException | ClassNotFoundException 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();
            }
        }

    }
}

完成。

向mysql插入数据

package com.wang.lesson02;

import com.wang.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
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();   //获取数据库连接
            st = conn.createStatement();    //获得SQL的执行对象

            String sql ="insert into users(id,name,password,email,birthday)"
                    +"values(4,'Michael','123456','214315@qq.com','2021-2-1');";
            int i = st.executeUpdate(sql);  //i代表受影响的行数
            if(i>0){
                System.out.println("插入成功!");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}

image-20211015145030188

报了异常,但是插入成功!

image-20211015145112419

删除数据

同样的,

package com.wang.lesson02;

import com.wang.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
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();   //获取数据库连接
            st = conn.createStatement();    //获得SQL的执行对象

            String sql ="delete from users where id=4";
            int i = st.executeUpdate(sql);  //i代表受影响的行数
            if(i>0){
                System.out.println("删除成功!");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}

image-20211015145822213

image-20211015150006703

更新数据

package com.wang.lesson02;

import com.wang.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
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();   //获取数据库连接
            st = conn.createStatement();    //获得SQL的执行对象

            String sql ="update users set name = '张三' where id=1";
            int i = st.executeUpdate(sql);  //i代表受影响的行数
            if(i>0){
                System.out.println("更新成功!");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}

image-20211015150813262

测试查询

package com.wang.lesson02;

import com.wang.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
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();
            st = conn.createStatement();

            //SQL
            String sql = "select * from users where id=1";

            rs = st.executeQuery(sql);//查询完毕会返回一个结果集

            while (rs.next()){
                System.out.println(rs.getString("name"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}

image-20211015152449469

SQL注入问题

sql存在漏洞,会被攻击导致数据泄露。SQL会被拼接

SQL注入即是指web应用程序对用户输入数据的合法性没有判断过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。

package com.wang.lesson02;

import com.wang.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class SQLInjection {
    public static void main(String[] args) {
        //login("张三","123456");  //正常登录
        login(" 'or '1=1"," 'or '1=1"); //sql注入
    }

    //登录业务
    public static void login(String username,String password){
        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtils.getConnection();
            st = conn.createStatement();

            //SQL
            String sql = "select * from users where name='"+username+"' and password='"+password+"'";

            rs = st.executeQuery(sql);//查询完毕会返回一个结果集

            while (rs.next()){
                System.out.println(rs.getString("name"));
                System.out.println(rs.getString("password"));
                System.out.println("==================================");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}

image-20211015154437109

PreParedStaterment对象

PreParedStaterment可以防止SQL注入,并且效率更高。

新增

package com.wang.lesson03;

import com.wang.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.util.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class TestInsert {
    public static void main(String[] args) {

        Connection conn = null;
        PreparedStatement st = null;
        
        try {
            conn = JdbcUtils.getConnection();

            //区别
            //使用 ? 占位符代替参数
            String sql = "insert into users(id,name,password,email,birthday) value(?,?,?,?,?)";
            st = conn.prepareStatement(sql);//预编译SQl,先写sql,然后不执行

            //手动给参数赋值
            st.setInt(1,4); // id 1代表第一个?
            st.setString(2,"赵匡胤");
            st.setString(3,"123456");
            st.setString(4,"3426527@qq.com");
            //  sql.Date 数据库的Date
            //  util.Date   Java的Date      new Date().getTime()获得时间戳
            st.setString(5, String.valueOf(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(conn,st,null);
        }
    }
}

image-20211015161829227

image-20211015161924835

删除

import com.wang.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class TestDelete {
    public static void main(String[] args) {

        Connection conn = null;
        PreparedStatement st = null;

        try {
            conn = JdbcUtils.getConnection();

            //区别
            //使用 ? 占位符代替参数
            String sql = "delete from users where id=?";
            st = conn.prepareStatement(sql);//预编译SQl,先写sql,然后不执行

            //手动给参数赋值
            st.setInt(1,4);

            //执行
            int i = st.executeUpdate();
            if(i>0){
                System.out.println("删除成功!");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,null);
        }
    }
}

image-20211015162813671

image-20211015162918866

更新

package com.wang.lesson03;

import com.wang.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class TestUpdate {
    public static void main(String[] args) {

        Connection conn = null;
        PreparedStatement st = null;

        try {
            conn = JdbcUtils.getConnection();

            //区别
            //使用 ? 占位符代替参数
            String sql = "update users set name=? where id=?";
            st = conn.prepareStatement(sql);//预编译SQl,先写sql,然后不执行

            //手动给参数赋值
            st.setString(1,"李四");
            st.setInt(2,2);

            //执行
            int i = st.executeUpdate();
            if(i>0){
                System.out.println("更新成功!");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,null);
        }
    }
}

image-20211015163213534

image-20211015163158447

查询

package com.wang.lesson03;

import com.wang.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

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=?";  //编写sql
            st = conn.prepareStatement(sql);// 预编译,不执行
            st.setInt(1,1);//传递参数
            rs = st.executeQuery();//执行

            if(rs.next()){
                System.out.println(rs.getString("name"));
            }
            
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}

image-20211015163814018

SQL注入

package com.wang.lesson03;

import com.wang.lesson02.utils.JdbcUtils;

import java.sql.*;

public class SQLInjection {
    public static void main(String[] args) {
        login("张三","123456");  //正常登录
        //login(" 'or '1=1"," 'or '1=1"); //sql注入 没有结果也没报错
    }


    //登录业务
    public static void login(String username,String password){
        Connection conn = null;
        PreparedStatement st = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtils.getConnection();

            //PreparedStatement 防止SQL注入
            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 (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}

PreParedStaterment防止SQL注入的本质:把传递进来的参数当作字符,假设其中存在转义字符,就直接忽略。

使用IDEA连接数据库

![img](https://raw.githubusercontent.com/wys49413/Warehouse/master/LWQW6`]E3I](5%7BX2K%602U~5A.png)

image-20211018084020078

image-20211018084132178

image-20211018084219388

更新数据

image-20211018084451066

事务

将user表copy到jdbcstudy数据库中。

image-20211018103018425

import com.wang.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class TestTransaction1 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement st = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtils.getConnection();
            //关闭自动提交,自动开启事务
            conn.setAutoCommit(false);

            String sql1 = "update user set money = money-100 where name ='a'";
            st = conn.prepareStatement(sql1);
            st.executeUpdate();
            String sql2 = "update user set money = money+100 where name ='b'";
            st = conn.prepareStatement(sql2);
            st.executeUpdate();

            //业务完毕,提交事务
            conn.commit();
            System.out.println("成功");


        } catch (SQLException e) {

            try {
                conn.rollback();//如果失败则回滚事务
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}

image-20211018103157403

执行成功!

代码实现

1.开启事务conn.setAutoCommit(false);

2.一组业务执行完毕,提交事务 conn.commit();

3.可以在catch语句中显示定义的回滚语句,默认失败就会回滚conn.rollback();

posted @ 2021-10-14 16:22  萘汝  阅读(67)  评论(0编辑  收藏  举报
我发了疯似的祝你好!