jdbc

JDBC

在这里插入图片描述
jdbc的demo

  1. 创建一个数据库
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@qq.com','1980-12-04'),
(2,'lisi','123456','lis@qq.com','1989-02-05'),
(3,'wangwu','123456','wangwu@qq.com','1990-10-06');
  1. 一个demo
    步骤总结:
    (1) 加载驱动:Class.forName(“com.mysql.jdbc.Driver”); 这个是固定写法
    (2) 连接数据库,需要用户名,密码,以及对应的url。url对应着jdbc:mysql://localhost:3306/数据库的名字?连接编码以及格式和安全连接。
  • 其中这个jdbc:后面的连接是为了同一编码格式
jdbc:mysql://localhost:3306/数据库名?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true 
// 统一代码的编码和数据库的编码。全部使用utf-8格式。
// 作用指定字符集的编码/解码的格式
useUnicode	默认为false	是否使用Unicode字符集,为true则是使用Unciode字符集
characterEncoding 要指定字符的编码集

mysql数据库使用的是gbk编码,而项目数据库使用的是utf8编码,这时候添加useUnicode=true&characterEncoding=UTF-8作用有两个方面

    1. 存储数据时:数据库存放项目数据会先用utf8格式将数据解码成字节码,然后再将解码后的字节码重新使用GBK编码存放到数据库中。
    1. 获取数据时:在从数据库中取数据时,数据库会先将数据库中的数据按GBK格式解码成字节码,然后再将解码后的字节码重新按utf8格式编码数据,最后再将数据返回给客户端
  • 特定的格式是解码变成字节码,字节码是重新按某种格式编码成数据
  • 在xml配置文件中配置数据库url时,要使用&的转义字符是==&==
  • autoReconnect=true : characterEncoding=utf8可以自动被识别为utf8mb4(当然也兼容原来的utf8),autoReconnect配置建议配上
mysql -- 3306 
jdbc:mysql:// 主机的地址:端口号/数据库名?参数1&参数2&参数3
// jdbc:mysql 为协议
// 如果是oralce -- 1521
jbdc:oracle:thin:@localhost:1521:sid

然后通过这个DriverManager.getConnection方法来连接数据库

// connection 代表数据库
// 数据库设置自动提交 connection.rollback(); 数据库自动提交
connection.commit(); // 事务提交
connection.setAutoCommit(); //  事务回滚

(3) 获取执行sql对象:Statement。通过createStatement来执行sql。excuteQuery来执行具体的sql

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

(4) 获取返回的结果集。消息查询出来的是一列一列的集合。

ResultSet查询的结果即:封装了所有的查询结果
// 获取指定的数据类型
resultSet.getObject(); // 在不知道列类型的情况下使用
// 如果知道列类型的情况就使用指定的类型
// 如:
resultSet.getString(); // 获取字符串等

resultSet.next(); // 移动到下一个数据,用于遍历,指针

(5) 释放连接

resultSet.close();
statement.close();
connection.close(); // 节约资源。用完关掉
<dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
    </dependencies>
import java.sql.*;

public class jdbcDemo01 {

    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        // 1.加载驱动
        Class.forName("com.mysql.jdbc.Driver"); // 固定写法,加载驱动

        // 2. 用户的信息和url
        String url = "jdbc:mysql://localhost:3306/jdbcStudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
        String username = "root";
        String password = "123";

        // 3.连接成功,数据库和对象
        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);

        while(resultSet.next()){
            System.out.println("id="+resultSet.getObject("id"));
            System.out.println("name="+resultSet.getObject("NAME"));
            System.out.println("pwd="+resultSet.getObject("PASSWORD"));
            System.out.println("email="+resultSet.getObject("email"));
            System.out.println("birth="+resultSet.getObject("birthday"));
        }
        // 6.释放连接
        resultSet.close();
        statement.close();
        connection.close();
    }
}
id=1
name=zhansan
pwd=123456
email=zs@qq.com
birth=1980-12-04
id=2
name=lisi
pwd=123456
email=lis@qq.com
birth=1989-02-05
id=3
name=wangwu
pwd=123456
email=wangwu@qq.com
birth=1990-10-06

CRUD的操作

// 增的操作
Statement st = conn.createStatement(); // 执行sql
String sql = "insert into user(...)values(...)"; 
// 执行增sql,增删改的sql,返回值是num
int num = st.executeUpdate(sql);
if(num > 0){
	sout("插入成功");
}

// 删除
Statement st = conn.createStatement();
String sql = "delete from user where id= 1"; // 删除from哪一张表的哪个id的那一行
int num = st.executeUpdate(sql);
if(num > 0){
	sout("删除成功");
}

// 改,set设置也是使用executeUpdate
Statement st = conn.createStatement();
String sql = "update user set name='' where name=''"; // 删除from哪一张表的哪个id的那一行
int num = st.executeUpdate(sql);
if(num > 0){
	sout("删除成功");
}

// 查询,使用executeQuery
Statement st = conn.createStatement();
String sql = "select* from user id= 1"; 
int num = st.executeQuery(sql);
where(rs.next()){
	// rs.getObject() ,根据获取列的数据类型,分别调用rs对应的方法,映射到java对象中
}

精简代码:使用工具类

package utils;

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
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{
        /**
         * 用Properties读取配置文件,一共有三步:
         * 创建Properties实例;
         * 调用load()读取文件;
         * 调用getProperty()获取配置。
         */

        try {
            // 使用static一开始就把这些配置信息加载出来
            // 把配置的信息通过加载器加载到这里来。
            InputStream is = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");

            // Java集合库提供了一个Properties来表示一组“配置”。由于历史遗留原因,Properties内部本质上是一个Hashtable,但我们只需要用到Properties自身关于读写配置的接口。
            Properties properties = new Properties();
            properties.load(is);
            // 获取配置
            driver = properties.getProperty("driver");
            url = properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");

            //1. 加载完配置之后,加载驱动
            Class.forName(driver);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    //  2. 获取连接DriverManager.getConnection
    // 把中间的封装成一个方法,由于这个是一个工具类,在外面直接可以调用的,所以使用static
    public static Connection getConnection() throws SQLException {
        // 这三个参数,没有传进来,所以提升上面这三个参数的作用域
        return DriverManager.getConnection(url,username,password);
    }


    // 3.释放连接资源
        /*resultSet.close();
        statement.close();
        connection.close();*/
    // 方法名释放:release,释放什么东西,释放这三个,所以是Connection,Statement ,ResultSet
    public static void release(Connection connection, Statement statement, ResultSet resultSet){
        if(resultSet!=null){
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(statement!=null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(connection!=null){
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

测试

import org.junit.Test;
import utils.JdbcUtils;

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

public class jdbcTest2 {
    Connection connection = null;
    Statement statement = null;
    ResultSet resultSet = null;
    @Test
    public void test2(){

        try {
            // 获取数据库连接
            connection = JdbcUtils.getConnection();
            // 获取sql的执行对象
            statement = connection.createStatement();
            // 写sql
//            String sql = "delete from users where id=5";
            // 查询的sql
            String sql ="select * from users where id = 1";

            // 执行sql
            /*int i = statement.executeUpdate(sql);
            if(i>0){
                System.out.println("删除成功!");
            }*/
            resultSet = statement.executeQuery(sql);
            // 会返回一个结果集,所以遍历出来
            while(resultSet.next()){
                String name = resultSet.getString("name");
                String password = resultSet.getString("password");
                String email = resultSet.getString("email");
                String birthday = resultSet.getString("birthday");
                System.out.println(name);
                System.out.println(password);
                System.out.println(email);
                System.out.println(birthday);
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(connection,statement, resultSet);
        }
    }
}
sql注入的问题

SQL注入的问题:在拼接sql时,有一些sql由于特殊的关系字符参与字符串的拼接,会造成安全性问题。
如:密码为:a or a=a; 后面是true,前面就算是错的,也可以成功

  • 解决sql注入的问题:使用PreparedStatement对象来解决
String sql = "select * from users where username='"+username+"'and password='"+password+"'";

这样会产生sql注入问题
解决方法:

  • 定义sql的时候:注意:sql的参数使用?作为占位符。如:select * from user where
    username = ?and password = ?;
  • 获取获取执行sql语句的对象 PreparedStatement Connection.prepareStatement(String sql)
  • 给?赋值:
    方法:setXxx(参数1,参数2)
    参数1: ?的位置编号 从1开始
    参数2:?的值
import utils.JdbcUtils;

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

public class jdbcTest3 {

    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement pst = null;
        try {
            // 1. 使用工具类去连接数据库
            connection = JdbcUtils.getConnection();
            // 2.写sql,使用?占位符来替代参数,防止sql注入
            String sql = "insert into users(id,name,password,email,birthday) values(?,?,?,?,?)";
            // 预编译sql,prepareStatement预编译sql,为了防止sql注入,把Statement改为了prepareStatement
            pst = connection.prepareStatement(sql);
            // 因为参数是用?占位符来替代,所以需要手动赋值
            // 第一个参数代表的是第几个?,第二个参数是?的值
            pst.setInt(1,4);
            pst.setString(2,"逆天而行");
            pst.setString(3,"2141423");
            pst.setString(4,"123144@qq.com");
            // setDate里面的源码int parameterIndex, java.sql.Date x,第二个参数是sql的Date,直接new一个sql的Date,
            // 也就是说要把这个给转换成sql的date,把util类的Date,getTime获取当前时间戳
            pst.setDate(5,new java.sql.Date(new Date().getTime()));

            // 执行sql,executeUpdate,使用之前的方法执行,sql需要放到这个里面
            // 但是使用prepareStatement不用吧sql放入executeUpdate
            int i = pst.executeUpdate();
            if(i>0){
                System.out.println("插入成功");
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            // 别忘记关闭资源
            JdbcUtils.release(connection,pst,null);
        }
    }
}

同理删除

 // 1. 使用工具类去连接数据库
            connection = JdbcUtils.getConnection();
            // 2.写sql,使用?占位符来替代参数,防止sql注入
            String sql = "delete from users where id=?";
            // 预编译sql,prepareStatement预编译sql,为了防止sql注入,把Statement改为了prepareStatement
            pst = connection.prepareStatement(sql);
            pst.setInt(1,5);
            // 执行sql,executeUpdate,使用之前的方法执行,sql需要放到这个里面
            // 但是使用prepareStatement不用吧sql放入executeUpdate
            int i = pst.executeUpdate();
            if(i>0){
                System.out.println("删除成功");
            }

修改

connection = JdbcUtils.getConnection();
            // 2.写sql,使用?占位符来替代参数,防止sql注入
            String sql = "update users set name = ? where id=?;";
            // 预编译sql,prepareStatement预编译sql,为了防止sql注入,把Statement改为了prepareStatement
            pst = connection.prepareStatement(sql);
            // 因为参数是用?占位符来替代,所以需要手动赋值
            // 第一个参数代表的是第几个?,第二个参数是?的值
            pst.setString(1,"子羽");
            pst.setInt(2,1);
            // 执行sql,executeUpdate,使用之前的方法执行,sql需要放到这个里面
            // 但是使用prepareStatement不用吧sql放入executeUpdate
            int i = pst.executeUpdate();
            if(i>0){
                System.out.println("修改成功");
            }
  • PreparedStatement防止sql注入的本质就是把传递进来的参数当做字符。

事务

要么都成功,要么都失败
ACID原则

  • 原子性:要么全部完成,要么全部不完成

  • 一致性:总数不变

  • 隔离性:多个进程互不干扰

  • 持久性:一旦提交不可逆,持久化到数据库

  • 隔离性的问题:

  • 脏读:一个事务读取到了另一个没有提交的事务

  • 不可重复读:在同一个事务内,读取到了别人插入的数据,导致前后读出来的结果不一致

  • 虚读:在一个事务内,读取到了别人插入的数据,导致前后读的结果不一样。

一个转账的操作

/*创建账户表*/
create table account(
    id int primary key auto_increment,
    name varchar(40),
    money float
);
# 插入测试的数据
insert into account(name, money) values ('A',1000);
insert into account(name, money) values ('B',1000);
insert into account(name, money) values ('C',1000);
import utils.JdbcUtils;

import javax.swing.*;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class Test4 {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        // 使用工具类连接数据库
        try {
            connection = JdbcUtils.getConnection();
            // 写sql
            // 关于事务的操作的测试
            // 关闭数据库的自动提交,自动会开启事务
            connection.setAutoCommit(false); // false是关闭了自动提交

            // A少了100
            String sql1 = "update account set money = money-100  where name='A'";
            // 预编译
            preparedStatement = connection.prepareStatement(sql1);
            // 执行sql
            preparedStatement.executeUpdate();

            // B+100
            String sql2 = "update account set money = money +100 where name='B'";
            // 编译,然后执行
            PreparedStatement preparedStatement1 = connection.prepareStatement(sql2);
            preparedStatement1.executeUpdate();

            // 提交,没有提交的话,数据是不会被持久化的
            connection.commit();
            System.out.println("成功");
        } catch (SQLException e) {
            // 如果失败,则默认回滚,可以不写,语句不会执行
//            connection.rollback();
            e.printStackTrace();
        }finally {
            JdbcUtils.release(connection,preparedStatement,resultSet);
        }
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值