01-数据库部分


1. Mysql数据模型

  • mysql是一个关系型数据库,所谓关系型数据库就是建立在关系模型上的数据库。
    • 都是使用表结构的,格式一致,容易维护
      
    • 都是使用通用的SQL语言进行操作,使用方便,可用于复杂的查询
      
    • 数据存储在外存中,安全
      

2.SQL分类

2.1 DDL(Data definition Language)

有以下几种

  • 对数据库的操作
    show database;//show出当前数据库的信息
    create databasse douyin1 if not exit;//保护性创建
    drop databas if exists user;//保护性删除数据库
    
    user douyin;//选择数据库
    select databse();//查看当前的数据库
  • 对表的操作(CRUD)
  • `创建(Create)`
    
    create table 表名(
    	字段名1 数据类型1
    	...
    );
  • 查询(Retrieve)
    show tables;//查询库中的表
    desc comments;//查询表的具体结构
  • 修改(Update)
    修改表名:rename to(alter table table_name rename to newname)
    添加一列数据:ADD:(alter table table_name rename add newcol datatype)
    修改数据类型modify:(alter table table_name modify colname new database)
    修改列名和数据类型:(alter table table_name change colname newcolname newdatatype)
    删除列:drop:(alter table drop colname)
  • 删除(Delete)
    drop tables if exists comments;//语法与库的是一致的

2.2 DML

  • 给指定的列添加数据:insert into table_name(col_1,col_2,...,col_n) values(value1,value2,value3,...,valuen)
  • 查询所有数据select * from table_name
  • 修改记录:update table_name set 列名1=值1,.. [where]
  • 删除记录:delete from table_name where

2.3 DQL(查询)

  • select 字段列表
  • from 表名列表
  • where 条件列表
  • group by 分组字段
  • having 分组后条件
  • order by 排序字段
  • limit:分页限定

2.3.1 基础查询

  • 查询多个字段
select 字段列表 from table_name;
select * from table; --查询所有的字段
  • 去除重复记录
select distinct 字段列表 from 表名;
  • 起别名
as:as可以省略

2.3.2 条件查询

主要是运用where关键字来对sql的查询结果进行限制

2.3.3 排序查询

主要是运用order by关键字来进行查询

select from table_name order by asc(desc) 排序字段名 [排序方式],排序字段名 [排序方式]
--多字段排序

2.3.4 聚合函数

  • 聚合函数:将一列数据作为一个整体,进行纵向计算

  • 聚合函数的分类

函数名 功能
count(列名) 统计数量(一般选用不为null的列)
max(列名) 最大值
min(列名) 最小值
sum(列名) 求和
avg(列名) 平均值
  • 聚合函数语法
select 聚合函数名(列名) from 表;

2.3.5 分组查询

  • 分组语句实例
select avg(score) from table_name group by sex having count(*)>2;

注意:分组之后查询的字段为聚合函数和分组字段,查询其他字段没有任何意义

其中having和where应该如何区分呢?

  • having对每一个分组进行过滤,是在分组之后进行的
  • where对每一条记录进行过滤,是在分组之前进行的
  • 对象不同

2.3.6 分页查询

其实就是用limit对查询量级进行限制

3.约束

3.1 约束的概念

  • 约束是作用于表中列上的规则,用于限制加入表的数据
  • 约束的存在保证了数据库中数据的正确性,有效性和完整性

3.2 约束的分类

约束名称 描述 关键字
非空约束 保证列中所有数据不能有null值 NOT NULL
唯一约束 保证列中所有数据各不相同 UNIQUE
主键约束 主键是一行数据的唯一标识,要求非空而且唯一 PRIMARY KEY
检查约束 保证列中的值满足某一条件 CHECK
默认约束 保存数据时未指定值则采用默认值 DEFAULT
外键约束 外键用来让两个表的数据之间建立连接,保证数据的一致性和完整性 FOREIGN KEY

3.3 外键的约束

外键:用来让两个表的数据之间建立联系,保证数据的一致性和完整性

  • 添加约束
create table table_name{
	列名 数据类型,
	...
	列名 数据类型
	[constraint] [外键名称] foreign key(外键列名) (外键字段名称) references 主表(主表列名); 
};
  • 外键约束下的主表与从表

    • 关于主表与从表,可以从依赖关系来看,如果一个表的字段是另一个表的索引(也就是通过这个表的字段来找到另一个表的信息),那么索引表称为是从表(很好理解,它这个字段不提供信息),信息所在表称为是主表(如果这个字段提供两个信息)
  • 删除外键约束

alter table table_name drop foreign key fk_key_table_table;
  • 增加外键约束
alter table sontable add constraint fk_key foreign key(colname) references maintable(colname);

4.数据库设计

  • 数据库设计的概念:根据业务系统的具体需求,结合我们所使用的DBMS,为这个业务系统构造出最优的数据存储模型
  • 建立数据库中的表结构表与表之间的关联关系的过程

4.1 一对多设计模式

  • 实现方式:在多的一方设立外键,指向一方的主键,将关系映射到主表上去

4.2 多对多设计模式

  • 实现方式:建立第三张中间表,中间表至少包含两个键,分别关联两方的主键

4.3 一对一设计设计模式

  • 实现方式:常见的有将有关的集合域拆成若干张表,以减少每张表的字段数,从而提高查询性能,在任意一方加入外键,关联另一方主键,并且设置外键为唯一即可.

5.多表查询

5.1 连接查询分类

  • 内连接:相当于查询A、B的交集数据
  • 外连接
    • 左外连接:相当于查询A表中所有数据和交集部分数据
    • 右外连接:相当于查询B表中所有数据和交集部分数据
  • 子查询

5.2 内连接

-- 隐式内连接
select name,sex,brief from table_name,table2_name where id1 = id2;
-- 显式内连接
select name,sex,brief from table_name [inner] join table2_name on table_name.id = table2_name.id;

5.3 外连接

-- 左外连接
select name,sex,brief from table1 [outer] left join table2 on table1.id = table2.id;
-- 右外连接
select name,sex,brief from table2 [outer] right join table2 on table1.id = table2.id;

5.4 子查询

  • 子查询的概念:查询中嵌套查询,称嵌套查询为子查询

  • 单行单列的查询结果:作为条件值,使用=!><等进行判断

select 字段列表 from 表 where 字段名 = (子查询)
select name from table where score = (select score from table where name = "张三" )
  • 多行单列的查询结果:作为条件值,用in等关键字进行条件判断
select name from table where id in (select id from table2 where tname = "t1" or tname = "t2")
  • 多行多列的查询结果:作为虚拟表
-- 当查询结果是表结构的时候,可以将其作为表结构,接在from后面进行查询
select name from (select * from table where name = "张三") where id > 35 ;

6.事务

6.1 事务简介

事务:是一种机制,一个操作序列,包含了一组数据库操作命令

事务把所有的命令作为一个整体一起向系统提交或者撤销操作请求,即这一组数据库命令要么同时成功,要么同时失败

事务是一个不可分割的工作逻辑单元(原子操作)

6.2 事务操作

  • 开启事务:给当前的指令序列打上标记,试执行指令序列,而不对数据库内部数据作持久化的修改
-- 开启事务
start transaction;
begin;
  • 提交事务:指令序列没有出现异常,可正常执行,对数据库内部数据作持久化的修改
-- 提交事务
commit;
  • 回滚事务:当事务操作出现异常时,事务操作回滚到开启事务之前的状态。
-- 回滚事务
rollback;
-- 示例代码
-- 转账操作,开启事务
begin;
-- 查询李四的金额
select money from account where id = 2;
-- 李四的金额 -50
update account set money = money - 50 where id = 2;
-- 张三的金额 +50
update account set money = money + 50 where id = 1;
-- 无异常,提交事务
commit;
-- 回显金额
select * from account;

6.3 事务四大特征(ACID)

原子性(Atomicity):事务是不可分割的最小操作单位,要么同时成功,要么同时失败

一致性(Consisitency):事务完成之时,必须使得所有的数据都保持一致的状态

隔离性(Isolation):多个事务之间,操作的可见性

持久性(Durability):事务一旦提交或者回滚,它对数据库中的数据的改变就是永久的

7. JDBC

7.1 JDBC简介

  • 使用Java语言操作关系型数据的一套API
  • 同一套java代码,操作不同的数据库
  • 所谓驱动:就是提供的jdbc中,对于不同数据库接口操作的实现类,这些实现类实现了接口

7.2 JDBC快速入门

import java.sql.*;

public class Main {
    public static void main(String[] args) {
        try{
            // 1.注册当前驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 2. 获取连接
            String url = "jdbc:mysql://127.0.0.1:3306/douyin?serverTimezone=GMT&useSSL=false";
            String user = "root";
            String pwd =  "123456";
            Connection conn  = DriverManager.getConnection(url,user,pwd);
            //3.定义sql语句,定义任意一句sql语句
            String sql = "update account set money  = money +50 where id = 2";
            //4.获取sql的对象
            Statement stmt =  conn.createStatement();
            //5.执行语句
            int num = stmt.executeUpdate(sql);
            System.out.println("受影响的行数"+num);
            //6.释放资源
            stmt.close();
            conn.close();
        }catch (ClassNotFoundException e){
            e.printStackTrace();
        }catch (SQLException e){
            e.printStackTrace();
        }
    }

}

7.3 JDBC API详解

7.3.1Connection

  • 普通执行SQL对象:statement createStatement()

  • 预编译SQL的执行对象:PreparedStatement preparedStatement(sql),一定程度上可以防止sql的注入

  • 执行存储过程的对象:callableStatement prepareCall(sql)

  • 事务管理

    • 要点:通过try-catch来限制commit和rollback的作用范围
    // 1.注册当前驱动
    Class.forName("com.mysql.cj.jdbc.Driver");
    // 2. 获取连接
    String url = "jdbc:mysql://127.0.0.1:3306/douyin?serverTimezone=GMT&useSSL=false";
    String user = "root";
    String pwd =  "123456";
    Connection conn  = DriverManager.getConnection(url,user,pwd);
    //3.定义sql语句,定义任意一句sql语句
    String sql_1 = "update account set money  = money +50 where id = 2";
    String sql_2 = "update account set money  = money +50 where id = 1";
      
    //4.获取sql的对象
    Statement stmt =  conn.createStatement();
    try{
        //5.执行语句
        conn.setAutoCommit(false);//开启事务
        stmt.execute(sql_1);
        stmt.execute(sql_2);
        //否则全部执行成功,提交该事务
        conn.commit();
    }catch (SQLException e){
        conn.rollback();
        e.printStackTrace();
    }
    //6.释放资源
    stmt.close();
    conn.close();
}catch (ClassNotFoundException e){
    e.printStackTrace();
}catch (SQLException e){
    e.printStackTrace();
}
      

7.3.2 Statement

  • int executeUpdate(sql):执行DML语句/DDL语句,返回DML语句影响的行数、DDL语句执行后也可能将会返回0
  • ResultSet executeQuery(sql):执行DQL语句,返回值ResultSet结果集对象
    • boolean next():将当前指针从当前位置向后移动一行,判断当前行是否是有效行
      • true:有效行,当前行有数据
      • false:无效行,当前行没有数据
    • xxx getxxx(参数):用来获取数据
      • 参数:int:列的编号,从1开始的
      • String:列的名称
try{
    // 1.注册当前驱动
    Class.forName("com.mysql.cj.jdbc.Driver");
    // 2. 获取连接
    String url = "jdbc:mysql://127.0.0.1:3306/douyin?serverTimezone=GMT&useSSL=false";
    String user = "root";
    String pwd =  "123456";
    Connection conn  = DriverManager.getConnection(url,user,pwd);
    // 3. 定义sql语句
    String sql="select * from account";
    //4. 创建执行sql的对象
    Statement stmt = conn.createStatement();
    //5. 执行sql
    ResultSet res = stmt.executeQuery(sql);
    while(res.next()){
        System.out.println(res.getString(1));
        System.out.println(res.getString(2));
        System.out.println(res.getDouble(3));
    }
    //6.释放资源
    stmt.close();
    conn.close();
}catch (ClassNotFoundException e){
    e.printStackTrace();
}catch (SQLException e){
    e.printStackTrace();
}

7.3.3 PreparedStatemtn

    // 1.注册当前驱动
    Class.forName("com.mysql.cj.jdbc.Driver");
    // 2. 获取连接
    String url = "jdbc:mysql://127.0.0.1:3306/douyin?serverTimezone=GMT&useSSL=false";
    String user = "root";
    String pwd =  "123456";
    Connection conn  = DriverManager.getConnection(url,user,pwd);
    // 3. 定义sql语句,用pre的写法的话,动态的数据应该要用?来替代
    String sql="select * from users where id = ? and password = ?";
    //4. 创建执行sql的对象
    //Statement stmt = conn.createStatement();
    PreparedStatement stmt = conn.prepareStatement(sql);
    //5. 执行sql
    stmt.setString(1,"1");
    stmt.setString(2,"2");
    ResultSet res = stmt.executeQuery();
    while(res.next()){
        System.out.println(res.getString(1));
        System.out.println(res.getString(2));
        System.out.println(res.getDouble(3));
    }
    //6.释放资源
    stmt.close();
    conn.close();
}catch (ClassNotFoundException e){
    e.printStackTrace();
}catch (SQLException e){
    e.printStackTrace();
}

preparedStatement可以有效地防止sql注入

  • 好处:①预编译SQL,性能将会更高②防止SQL注入,将敏感字符串进行转义
  • 预编译功能开启:useServerPrepStmts = true
  • MYSQL执行SQL语句的路径:检查SQL语法->编译MYSQL->执行MYSQL
    • 对于单独的一条SQL,MYSQL都要单独处理这样的过程,耗时较长。
    • 预编译后话就只需要检查一次,编译一次,即可

7.4 数据库连接池&Druid(德鲁伊)

  • 数据库连接池是一个容器,负责分配,管理数据库连接(Connection)

  • 它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个

  • 释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库而引起的数据库连接遗落

  • 好处

    • 资源可重用,也就是复用连接
    • 提升系统的响应速度
    • 避免数据库连接遗落
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/douyin?serverTimezone=GMT&useSSL=false&allowPublicKeyRetrieval=true
username=root
password=123456
# 初始化连接池数量
initialSize = 5
# 最大连接数
maxActive = 10
# 最大等待时间
maxWait = 3000
@Test
public void test(){
    try {
        // 1.加载配置文件
        Properties prop = new Properties();
        prop.load(new FileInputStream("src/connection.properties"));
        // 2.获取连接池对象
        DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
        // 3.获取数据库连接
        Connection connection = dataSource.getConnection();
        System.out.println(connection.toString());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

7.5 JDBC练习

package testdemo;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.junit.Test;

import javax.sql.DataSource;
import java.io.FileReader;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;
import java.util.Vector;

public class test {
    /*要点:1.连接池的使用*/
    /*sql的编写(pre)*/
    @Test
    public void testSelectAll(){//测试查询
        try{
            //1.获取connection,利用德鲁伊连接池
            Properties properties = new Properties();
            properties.load(new FileReader("src/connection.properties"));
            DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
            Connection connection = dataSource.getConnection();
            //2.编写sql
            String sql="select * from tb_brand";
            //3.执行sql
            PreparedStatement stmts = connection.prepareStatement(sql);
            ResultSet resultSet = stmts.executeQuery();
            //4.定义数据结构,将其存储起来
            Vector<Brand> brands = new Vector<>();
            while(resultSet.next()){
                Brand brand = new Brand();
                brand.setId(resultSet.getInt(1));
                brand.setBrand_name(resultSet.getString(2));
                brand.setCompany_name(resultSet.getString(3));
                brand.setOrdered(resultSet.getInt(4));
                brand.setDescription(resultSet.getString(5));
                brand.setStatus(resultSet.getBoolean(6));
                brands.add(brand);
            }
            //5.输出结果
            for (Brand brand : brands) {
                System.out.println(brand.toString());
            }
            stmts.close();
            connection.close();
        } catch (Exception e){
            e.printStackTrace();
        }
    }//PASS

    @Test
    public void testDeleteData(){
        try{
            //1.获取connection,利用德鲁伊连接池
            Properties properties = new Properties();
            properties.load(new FileReader("src/connection.properties"));
            DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
            Connection connection = dataSource.getConnection();
            //2.编写sql
            String sql="delete from tb_brand where id = ?";
            //3.执行sql
            PreparedStatement stmts = connection.prepareStatement(sql);
            int deleteNum = 3;//删除id为2的,并且回显
            stmts.setInt(1,deleteNum);
            int count = stmts.executeUpdate();
            if(count>0){
                System.out.println("删除成功");
            }else{
                System.out.println("删除失败");
            }
            stmts.close();
            connection.close();
            testSelectAll();
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    @Test
    public void testUpdateData(){
        try{
            //1.获取connection,利用德鲁伊连接池
            Properties properties = new Properties();
            properties.load(new FileReader("src/connection.properties"));
            DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
            Connection connection = dataSource.getConnection();
            //2.编写sql
            String sql="update tb_brand set brand_name = ? where id = 1";
            //3.执行sql
            PreparedStatement stmts = connection.prepareStatement(sql);
            String newBrandName = "newName";
            stmts.setString(1,newBrandName);
            int count = stmts.executeUpdate();
            if(count>0){
                System.out.println("更新成功");
            }else{
                System.out.println("更新失败");
            }
            stmts.close();
            connection.close();
            testSelectAll();
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    @Test
    public void testAddData(){
        try{
            //1.获取connection,利用德鲁伊连接池
            Properties properties = new Properties();
            properties.load(new FileReader("src/connection.properties"));
            DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
            Connection connection = dataSource.getConnection();
            //2.编写sql
            String sql="insert into tb_brand values (?,?,?,?,?,?)";
            //3.执行sql
            PreparedStatement stmts = connection.prepareStatement(sql);
            stmts.setInt(1,4);
            stmts.setString(2,"5");
            stmts.setString(3,"6");
            stmts.setInt(4,2);
            stmts.setString(5,"8");
            stmts.setBoolean(6,true);
            int count = stmts.executeUpdate();
            if(count>0){
                System.out.println("增加成功");
            }else{
                System.out.println("增加失败");
            }
            stmts.close();
            connection.close();
            testSelectAll();
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    @Test
    public void testPath(){//不需要模块名
        System.out.println(System.getProperty("user.dir"));
    }
}

sql代码

use douyin;
-- 删除库中已经存在的重名表
drop table if exists tb_brand;
-- 创建表
create table tb_brand(
    -- id 主键
    id int primary key auto_increment,
    -- 品牌名称
    brand_name varchar(10) not null ,
    -- 企业名称
    company_name varchar(10) not null,
    -- 排序字段
    ordered int,
    -- 描述信息
    description varchar(100),
    -- 状态: false:禁用 true:可用
    status bool
);
-- 添加一条初始数据
insert into tb_brand (brand_name, company_name, ordered, description, status)
values               ("1","1",1,"1",true),
                     ("2","2",2,"2",true),
                     ("3","3",3,"3",true);
-- 校验数据
select * from tb_brand;

8. Maven

8.1 简介

  • 提供了一套标准化的项目结构
  • 提供了一套标准化的构建流程
  • 提供了一套管理依赖工具
  • 本质上管理和构建JAVA项目的工具
  • Apache Maven 是一个项目管理和构建工具,它基于项目对象模型(Project Obiject Model)的概念,通过一小段描述性信息来管理项目的构建,报告和文档

8.2 基本使用

  • 编译指令:mvn compile
  • 清理指令:mvn clean
  • 打包当前项目:mvn package
  • 自动测试:mvn test
  • 将自己的包安装到本地仓库:mvn install

8.3 Maven生命周期

  • Maven构建项目生命周期描述的是一次构建过程中经历了多少事件
  • Maven对项目构建的生命周期划分为3套
    • clean:清理工作
    • default:核心工作,例如编译,打包等
    • site:产生报告

8.4 Maven坐标

  • 什么是坐标
    • Maven中的坐标是资源的唯一标识符
    • 使用坐标来定义项目或者引入项目中需要的依赖项
  • Maven坐标的主要组成
    • groupid:定义当前Maven项目属于的组织名称(比如com.alibaba)
    • artifactId:定义当前Maven项目名称(通常是模块名称)
    • version:定义当前项目版本号

8.5 依赖范围

  • 可以通过设置坐标的依赖范围(scope),可以设置对应jar包的作用范围,编译环境,测试环境,运行环境
依赖范围 编译classpath 测试classpath 运行classpath 例子
compile Y Y Y logback
test - Y - Junit
provided Y Y - servlet-api
runtime - Y Y jdbc驱动
system Y Y - 存储在本地的jar包
import 引入Dependenc yManagement
  • 编译环境:可以在src下的所有代码文件下使用
  • 测试环境:可以在test下的所有代码文件下使用
  • 运行环境:打包后的代码文件下使用
  • 默认为compile

9. Mybatis

9.1 Mybatis简介

  • 持久层框架,用于优化JDBC的开发
  • 持久层:负责将数据保存到数据库的那一层代码
    • JAVAEE三层架构:表现层、业务层、持久层
    • 可以理解为与数据库相关的代码被集中封装在持久层
  • 框架:是一个半成品的软件吗,是一套可重用的、通用的、软件基础代码模型
  • 在框架的基础之上构建软件使得编写更加高效、规范、拓展、可通用
  • 框架 = 反射+注解+设计模式
  • JDBC的缺点
    • 代码中存在硬代码,将服务器路由等信息以字符串的形式写入到代码中去了
    • SQL语句代码手动设置
    • 需要手动设置参数
    • 需要手动封装结果
  • Mybatis的作用:免除了所有的JDBC代码以及设置参数和获取结果集的操作

9.2 快速入门

9.2.1 导入mybatis及基础包

  • 目前发现在每次新建项目后,IDEA的maven路径总是会变化,因此在导入依赖前先修改路径。
<dependencies>
    <!-- 导入mybatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.5</version>
    </dependency>
    <!-- 导入mysql驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.15</version>
    </dependency>
    <!-- 导入junit -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope>
    </dependency>
    <!-- 导入slf4j -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.2</version>
    </dependency>
    <!-- 导入logback-core-->
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-core</artifactId>
        <version>1.1.7</version>
    </dependency>
    <!-- 导入logback-classic-->
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.1.7</version>
    </dependency>
</dependencies>

9.2.2 从XML中构建SQLSessionFactory

  • XML中需要配置的信息有:数据库连接信息
<!-- 数据库连接设置 -->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/douyin?serverTimezone=GMT&amp;useSSL=false&amp;allowPublicKeyRetrieval=true"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>

9.2.3 编写映射的sql.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
    namespace:命名空间
    resultType:将来将要返回的数据类型(已经封装)
    select id:表示该sql是用来干啥的,标识符
-->
<mapper namespace="test">
    <select id="selectAll" resultType="pojo.Brand">
        select * from tb_brand;
    </select>
</mapper>

9.2.4 将写好的sql.xml配置到mybatis配置文件中去

<mappers>
    <!--加载sql的映射文件,注意路径,这里是平级的-->
    <mapper resource="UserMapper.xml"/>
</mappers>

9.2.5 加载mybatis配置文件,获取SQLSessionFactory

@Test
public void mybatisTest(){
    String resource = "mybatis-config.xml";//此处修改为刚才写的mybatis配置文件路径
    InputStream inputStream = null;
    try {
        inputStream = Resources.getResourceAsStream(resource);//解析文本文件,并以字节输入流的形式传入
    } catch (IOException e) {
        e.printStackTrace();
    }
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//以刚才得到的字节流信息为基础,建立SQLSessionFactory对象
    //2.获取sql执行对象
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //3.执行sql
    List<Brand> users = sqlSession.selectList("test.selectAll");//填入sql映射的唯一标识
    //4.释放资源
    sqlSession.close();
    //5.校验数据结构
    System.out.println(users);
}

9.3 Mapper代理开发

9.3.1 定义与SQL映射文件同名的Mapper接口,并且将Mapper接口与SQL映射文件放在同一目录下

  • 简单来说,就是为了达到编译后的.class文件和xml配置文件在同一路径下,必须修改包名和目录结构,将resources下的目录结构和src下的目录结构层次设置为一致的,然后就可以了。
  • 如图所示

9.3.2 设置SQL映射文件的namespace属性为Mapper接口全限定名

<mapper namespace="com.lumxi.mapper.UserMapper">
    <select id="selectAll" resultType="com.lumxi.pojo.Brand">
        select * from tb_brand;
    </select>
</mapper>

修改namespace即可

9.3.3 在Mapper接口中定义方法,方法名就是SQL映射文件中sql语句的id,并保持参数类型和返回值类型一致

public interface UserMapper {
   List<Brand> selectAll();
   
}

9.3.4 编码

@Test
public void mapperTest(){
    String resource = "mybatis-config.xml";//此处修改为刚才写的mybatis配置文件路径
    InputStream inputStream = null;
    try {
        inputStream = Resources.getResourceAsStream(resource);//解析文本文件,并以字节输入流的形式传入
    } catch (IOException e) {
        e.printStackTrace();
    }
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//以刚才得到的字节流信息为基础,建立SQLSessionFactory对象
    //2.获取sql执行对象
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //3.执行sql
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    List<Brand> brands = userMapper.selectAll();
    //4.释放资源
    sqlSession.close();
    //5.校验数据结构
    System.out.println(brands);
}
  • 如果Mapper接口名称与SQL映射文件名称相同,并在同一目录下,则可以使用包扫描的方式简化SQL映射文件的加载
<mappers>
    <!--加载sql的映射文件,注意路径,这里是平级的-->
    <!--<mapper resource="com/lumxi/mapper/UserMapper.xml"/>-->
    <!-- 当遵守了以上开发规范后,可以使用下列的方式,直接扫描包内所有资源文件-->
    <package name="com.lumxi.mapper"/>
</mappers>

9.4 核心配置文件简介

  • environments

  • ```xml

    <environments default="test">
        <environment id="test">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <!-- 数据库连接设置 -->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/douyin?serverTimezone=GMT&amp;useSSL=false&amp;allowPublicKeyRetrieval=true"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    
    
    ## 9.5 案例实战
    
    - 编码套路
      - 编写接口方法:Mapper接口
      - 确定参数
      - 确定返回值
      - 编写SQL语句
      - 单元测试
    
    ```xml
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <!--
        namespace:命名空间
        resultType:将来将要返回的数据类型(已经封装)
        select id:表示该sql是用来干啥的,标识符
    
    -->
    
    
    <mapper namespace="com.lumxi.mapper.BrandMapper">
        <resultMap id="brandResultMap" type="com.lumxi.pojo.Brand"> <!--注意这里要写成全限制名-->
            <!--
                id:完成主键字段的映射
                    column:     数据表的列名
                    property:   实体类的属性名
                result:用来映射一般字段
                    column:     数据表的列名
                    property:   实体类的属性名
            -->
            <result column="brand_name" property="brandName" />
            <result column="company_name" property="companyName" />
        </resultMap>
    
        <!--不接收参数-->
        <select id="selectAll" resultMap="brandResultMap">
            select * from tb_brand;
        </select>
    
        <!--接收动态参数 其中#被mysql服务器解析为? 而$则是直接将字符串拼入sql(有sql注入的风险)-->
        <select id="selectById" parameterType="int" resultMap="brandResultMap">
            select * from tb_brand where id = #{id};
        </select>
    
        <!-- 简单条件查询 -->
        <!--<select id="selectByCondition" resultMap="brandResultMap">
            select *
            from tb_brand
            where      status =          #{status}
              and brand_name   like #{brandName}
              and company_name like #{companyName};
        </select>-->
    
        <!-- SQL语句会随着用户的输入或者外部条件的变化而变化,称之为动态SQL -->
        <!-- Mybatis对动态SQL有很强大的支撑-->
        <!-- if choose(when,otherwise) trim(where,set) foreach-->
        <select id="selectByCondition" resultMap="brandResultMap">
            select *
            from tb_brand
            <where>
                <if test="status != null">
                    and status = #{status}
                </if>
    
                <if test="brandName != null and companyName !='' ">
                    and brand_name   like #{brandName}
                </if>
    
                <if test="companyName != null and companyName != ''">
                    and company_name like #{companyName}
                </if>
    
            </where>
        </select>
    
        <!--单条件查询,使用switch-->
        <select id="selectByConditionSingle" resultMap="brandResultMap">
            select * from tb_brand
            <where>
                <choose>
                    <when test="status != null">
                        status = #{status}
                    </when>
                    <when test="brandName!=null and brandName!=''">
                        brand_Name like #{brandName}
                    </when>
                    <when test="companyName!=null and companyName!=''">
                        company_name like #{companyName}
                    </when>
                </choose>
            </where>
        </select>
    
        <!-- 将主键写回对象属性 -->
        <insert id="add" useGeneratedKeys="true" keyProperty="id">
            insert into tb_brand ( brand_name, company_name, ordered, description, status)
            values (#{brandName},#{companyName},#{ordered},#{description},#{status});
        </insert>
    
        <!-- 修改全部字段-->
        <update id="update">
            update tb_brand set
            brand_name = #{brandName},
            company_name = #{companyName},
            ordered = #{ordered},
            description = #{description},
            status = #{status}
            where id = #{id};
        </update>
    
        <!-- 动态修改 -->
        <update id="updateByCondition">
            update tb_brand
            <set>
                <if test="brandName!=null and brandName!=''">
                    brand_name = #{brandName},
                </if>
                <if test="companyName!=null and companyName!=''">
                    company_name = #{companyName},
                </if>
                <if test="ordered!=null">
                    ordered = #{ordered},
                </if>
                <if test="description!=null and description!=''">
                    description = #{description},
                </if>
                <if test="status!=null">
                    status = #{status}
                </if>
            </set>
            where id = #{id};
        </update>
    
        <delete id="deleteById">
            delete from tb_brand where id = #{id};
        </delete>
        
        <delete id="deleteByIds">
            delete from tb_brand where id in
            <foreach collection="ids" item="id" separator="," open="(" close=")">
                #{id}
            </foreach>
            ;
        </delete>
        <!--
            关于底层Params注解的注入方式,首先会检测有多少个参数,Mybatis会自动为这些含有@Param注解的
            参数分配键名,比如说有3个:@Param("a"),@Param("b"),@Param("c")
            就会为a,b,c分配arg0,arg1,arg2,或者是param1,param2,param3(注意下标),这几个键值
            然后这几个键值作为映射的键,其对应的键值就是在其后传入的参数
            因此:通过@Param来替换这些难懂的键名
        -->
    
    
    
    </mapper>
package com.lumxi.mapper;

import com.lumxi.pojo.Brand;
import org.apache.ibatis.annotations.Param;

import java.util.List;
import java.util.Map;

public interface BrandMapper {
    List<Brand> selectAll();
    Brand selectById(int id);
    /*第一种,使用@Param进行元素注入*/

    /**
     * 条件查询
     *      * 散装参数(要使用注解),当需要多个参数时,需要用@Param进行注解
     *      * 对象参数
     *      * Map对象参数
     * @param status
     * @param companyName
     * @param brandName
     * @return
     */
    List<Brand> selectByCondition(@Param("status")boolean status,
                                  @Param("companyName")String companyName,
                                  @Param("brandName")String brandName);
    /*第二种,由于映射SQL文件已经做过了别名转换,因此数据库列名和对象属性名能够一一对应,因此直接传入Brand*/
    List<Brand> selectByCondition(Brand brand);
    /*第三种,与第二种同理*/
    List<Brand> selectByCondition(Map map);

    List<Brand> selectByConditionSingle(Brand brand);//任意单条件查询

    void add(Brand brand);

    int update(Brand brand);

    int updateByCondition(Brand brand);

    void deleteById(int id);

    void deleteByIds(@Param("ids") int[] ids);

}

文章作者: 穿山甲
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 穿山甲 !
  目录