Bootstrap

Java之JDBC,Maven,MYBatis

前言

就是用来操作数据库的

1.JDBC快速入门

注意在使用前一定要导入jar包
在这里插入图片描述
在模块那里新建目录,新建lib,粘贴复制jar包,我这个jar设置的是模块有效

package test1017;

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

public class test {
    public static void main(String[] args) throws Exception {
        //注册驱动
        Class.forName("com.mysql.cj.jdbc.Driver");

        //获取连接
        String url="jdbc:mysql://127.0.0.1:3306/test";//最后一个为数据库名?useSSL=false
        String username="root";//用户名
        String password="kl12151215";//密码
        Connection conn=DriverManager.getConnection(url,username,password);

        //获取sql对象
        Statement stmt=conn.createStatement();


        String sql="insert into emp3 values('bb',2)";//sql语句

        //执行sql
        int count=stmt.executeUpdate(sql);//executeUpdate只能用于INSERT、UPDATE、DELETE
        System.out.println(count);
        //释放资源
        stmt.close();
        conn.close();
    }
}

在这里插入图片描述
在这里插入图片描述
就这样我们就可以操作了

2.JDBC之API

2.1DriverManager

作用就是
1.注册驱动
2.获取数据库连接

Connection conn=DriverManager.getConnection(url,username,password);

比如这个就是获取数据库连接
在这里插入图片描述
而这个forName,其实底层调的就是DriverManager的注册驱动作用

然后就是mysql5之后的驱动包,可以不用写注册驱动了
在这里插入图片描述

//        Class.forName("com.mysql.cj.jdbc.Driver");

意思是把这个省略掉,也可以运行

然后就是链接的时候,如果链接的是本机的mysql服务器,而且默认端口号为3306.则就可以省略这两个不写

//        String url="jdbc:mysql://127.0.0.1:3306/test";//最后一个为数据库名?useSSL=false
        String url="jdbc:mysql:///test";//最后一个为数据库名

然后就是可以在后面写上useSSL=false,解决一些警告提示,但是高版本的没有警告提示

String url="jdbc:mysql:///test?useSSL=false";//最后一个为数据库名

如果还要继续配置参数,加上&继续添加就可以了

2.2 Connection

Connection
1.就是获取执行的sql对象,已经用过了
2.就是事务管理

        String sql1="insert into emp3 values('bb',2)";//sql语句
        String sql2="insert into emp3 values('cc',1)";//sql语句
        try {
            //开始事务
            conn.setAutoCommit(false);
            //执行sql
            int count1=stmt.executeUpdate(sql1);
            int count2=stmt.executeUpdate(sql2);
            System.out.println(count1);
            System.out.println(count2);
            //提交事务
            conn.commit();
        } catch (Exception e) {
        	conn.rollback();
            e.printStackTrace();
        }
conn.setAutoCommit(false);

就是开启事务,设置为false的意思就是需要手动提交事务,true就是自动提交事务
commit就是我们手动写的提交事务

至于回滚事务的话,如果出错了就抛异常吧,反正也不会真正执行的,都是假的执行,只有提交了才是真正的执行,抛到异常那里,在回滚,回滚的话,就算在自己这个用户也是无法看到变化的,不回滚的话,那么自己就会看到异常前的sql语句带来的变化

2.3 Statement

Statement有两个方法

stmt.executeUpdate()执行的是DML和DDL语句,返回值是语句影响的行数,一般来说,执行失败了,就会返回0,但是DDL中删除的操作,执行成功返回的也是0

stmt.executeQuery()执行的是DQL语句,就是查询语句,返回值是ResultSet

DML语句

Statement stmt=conn.createStatement();
        String sql1="update emp3 set name ='cc' where name = 'aa' ";//sql语句
        //开始事务
        conn.setAutoCommit(false);
        //执行sql
        int count1=stmt.executeUpdate(sql1);
        System.out.println(count1);

在这里插入图片描述

        if(count1>0)
        {
            System.out.println("修改成功");
        }
        else {
            System.out.println("修改失败");
        }

再加上这个就更完美了

DDL语句

        String sql1="create database aaaa ";//sql语句

在这里插入图片描述
返回1就是执行成功

        String sql1="drop database aaaa ";//sql语句

在这里插入图片描述
而drop时,成功的返回值就是0

ResultSet就是stmt.executeQuery()的返回值
它指向的就是那个你打印出的那个表
在这里插入图片描述

它一开始指向的name那一行,然后它有方法
next()方法就是将指向的光标下移一行,然后就是返回值,如果为有效行的话,返回true,反之

xxx getXxx(参数) :这个就是获取数据
xxx:是数据类型,如:int getInt(参数) 表明你要获取的数据是int类型的
参数:可以是int,代表列的编号
或者String:代表列的名称

public class test {
    public static void main(String[] args) throws Exception {
        String url="jdbc:mysql:///test?useSSL=false";//最后一个为数据库名
        String username="root";//用户名
        String password="kl12151215";//密码
        Connection conn=DriverManager.getConnection(url,username,password);
        //获取sql对象
        Statement stmt=conn.createStatement();
        String sql1="select * from emp3";//sql语句
        //执行sql
        ResultSet rs=stmt.executeQuery(sql1);
        while(rs.next())
        {
            int id=rs.getInt(2);
            String name=rs.getString(1);

            System.out.println(id);
            System.out.println(name);
            System.out.println("----------------");
        }
        //释放资源
        rs.close();//这下rs也要释放资源
        stmt.close();
        conn.close();
    }
}

在这里插入图片描述

这样的话,我们定义一个类,就可以储存这些数据了
然后定义一个链表,就可以全部数据存储了

            int id=rs.getInt("dep_id");
            String name=rs.getString("name");

或者这样写也是一样的

2.4PreparedStatement

1.这个可以预编译sql语句,第二这个可以防止sql注入问题

sql注入问题就是你登录的时候,账号乱写,然后密码写入一些特定的sql语句,让我们登录成功

比如密码输入 'or ‘1’ = '1

sql注入演示

在这里插入图片描述

我们这里假设name就是用户,dep_id就是密码

        String name="bb";//用户名
        String dep_id="2";
        String sql1="select * from emp4 where name='' and dep_id= '' ";

先这样

        String sql1="select * from emp4 where name=' " +name+" ' and dep_id= '  "  +dep_id+"' ";

再把name插进去,这样sql语句就写好了

        String name="bb";//用户名
        String dep_id="2";
        String sql1="select * from emp4 where name='"+name+"'and dep_id= '"+dep_id+"'";//注意的是,就是空格不要太大,不然读不出来
        ResultSet rs=stmt.executeQuery(sql1);
        if(rs.next())
        {
            System.out.println("登录成功");
        }else{
            System.out.println("登录失败");
        }

在这里插入图片描述
下面我们将pid_t换成 'or ‘1’ = '1

        String dep_id="'or '1' = '1";

在这里插入图片描述
结果还是这样的

为什么呢

我们看看最后的sql语句就知道了

select * from emp4 where name='bb'and dep_id= ''or '1' = '1'

可以看出,因为’1’ = '1’始终为真,所以,这个sql语句就为真,所以就会打印出所有东西,所以就会登录正确

因为这个密码改变了sql语句的意思,所以登录成功了,所以我们引入PreparedStatement,就可以防止了

PreparedStatement演示

public class test {
    public static void main(String[] args) throws Exception {
        String url="jdbc:mysql:///test?useSSL=false";//最后一个为数据库名
        String username="root";//用户名
        String password="kl12151215";//密码
        Connection conn=DriverManager.getConnection(url,username,password);

        Statement stmt=conn.createStatement();
        String name="bb";//用户名
        String dep_id="'or '1' = '1";
//        String dep_id="aa";
        String sql1="select * from emp4 where name=? and dep_id=?";//首先密码和用户我们用?替代
        //PreparedStatement对象通过conn获取
        PreparedStatement pstmt=conn.prepareStatement(sql1);//这里要传入sql语句

        pstmt.setString(1,name);
        pstmt.setString(2,dep_id);//给?设置值

        ResultSet rs=pstmt.executeQuery();//这里就不需要传sql了

        if(rs.next())
        {
            System.out.println("登录成功");
        }else{
            System.out.println("登录失败");
        }
        rs.close();
        stmt.close();
        conn.close();
    }
}

在这里插入图片描述
这样我们就解决了sql注入问题

它是怎么解决的呢
它其实是把单引号转义了,让它就是一个’'里面的一个正常的数据,不会产生’‘

select * from emp4 where name='bb' and dep_id= '\'or \1\ = \1';#'or '1' = '1

下面讲一下预编译的问题

sql语句在执行的过程中,会经历检查sql语法,编译sql,执行sql的步骤

而预编译就是我们在执行到PreparedStatement pstmt=conn.prepareStatement(sql1);的时候,就已经检查sql语法,编译sql了,后面设置?的时候,只需要替换执行sql就可以了

这样的话,我们执行两条sql语句的话,不用PreparedStatement 的话,我们就要走两遍检查sql语法,编译sql,执行sql

用了PreparedStatement ,检查sql语法,编译sql走一遍,,执行sql走两遍就可以了

但是要开启预编译的话,要输入useServerPreStmts=true
要设置这个

        String url="jdbc:mysql:///test?useSSL=false&useServerPreStmts=true";

2.5 数据库连接池

数据库连接池就和线程池是一样的,允许程序重复使用一个现有的数据库链接,而不是重新在建立一个

在这里插入图片描述

这个就是配置文件

public class test {
    public static void main(String[] args) throws Exception {
        //导入jar包
        //lib文件
        //定义配置文件
        //文件
        //加载配置文件
        Properties prop=new Properties();
        prop.load(new FileInputStream("test1017/src/druid.properties"));//路径是相对路径
        //获取连接池对象
        DataSource dataSource= DruidDataSourceFactory.createDataSource(prop);
        //获取数据库连接
        Connection connection=dataSource.getConnection();
        System.out.println(connection);
       
    }
}

在这里插入图片描述
一般来说,有了数据库连接池,我们就不需要自己手动去连接本地的数据库了,它自己会链接了,因为配置文件都写好了

3.实操

public class Brand {
    String name;
    String dep_id;

    public String getName() {
        return name;
    }

    public String getDep_id() {
        return dep_id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setDep_id(String dep_id) {
        this.dep_id = dep_id;
    }

    public Brand(String name, String dep_id) {
        this.name = name;
        this.dep_id = dep_id;
    }

    public Brand() {
    }
}

定义一个类来存每行
定义一个链表来存整个表

public class test {
    public static void main(String[] args) throws Exception {
        //导入jar包
        //lib文件
        //定义配置文件
        //文件
        //加载配置文件
        Properties prop=new Properties();
        prop.load(new FileInputStream("test1017/src/druid.properties"));

        //获取连接池对象
        DataSource dataSource= DruidDataSourceFactory.createDataSource(prop);

        //获取数据库连接
        Connection conn=dataSource.getConnection();
        
        //sql
        String sql="select * from emp4";
        
        //获取pstmt
        PreparedStatement pstmt=conn.prepareStatement(sql);
        
        //设置?参数
        
        //执行
        ResultSet rs=pstmt.executeQuery();
        
        //然后存储
            
    }
}

这个是查询的操作,或者是填充的操作

添加操作

insert into emp4(name dep_id) values(?,?);//有id的话,不用写,因为是默认自增长的

修改数据

update emp4
set name=?,
	dep_id=?
where id=?

删除

delete from emp4 where id=?

4. maven

maven是一个项目管理和构建的工具
它的项目结构,构建流程,还有依赖管理都是很统一的

下面讲一下maven的构建
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
给test添加resources
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
xml里面可以导入jar包

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

<!--当前项目的坐标-->
    <groupId>com.itheima</groupId>
    <artifactId>test1</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

<!--导入mysql的jar包-->
        <dependencies>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.33</version>
            </dependency>

            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.12</version>
            </dependency>

            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
                <scope>test</scope>
<!--scope的意思是说明jar的作用范围,所以这样只有test,测试环境,可以用junit,不写这个就是默认全部范围的-->
            </dependency>

        </dependencies>



</project>

比如这样

然后就可以写代码了

在java里面新建软件包,然后建java类就可以了

CTRL+A是全选

5.MyBatis

5.1查询

在这里插入图片描述


drop table if exists tb_brand;
create table tb_brand
(
	#主键
    id int primary key auto_increment,
    #品牌名称
    brand_name varchar(20),
	#企业名称
    company_name varchar(20),
    #排序字段
    ordered int,
    #描述信息
    description varchar(100),
    #状态  0:禁用  1:启用
    status   int
);
insert into tb_brand(brand_name,company_name,ordered,description,status)
 values ('三只松鼠','三只松鼠股份有限公司',5,'好吃不上火',0),
 ('华为','华为技术有限公司',108,'华为致力于把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能世界',1),
 ('小米','小米科技有限公司',50,'are you ok',1);
SELECT * FROM tb_brand;


package com.itheima.pojo;

public class Brand {
    private int id ;
    private String brand_name  ;
    private String company_name  ;
    private String ordered        ;
    private String description    ;
    private int status       ;

    public int getId() {
        return id;
    }

    public String getBrand_name() {
        return brand_name;
    }

    public String getCompany_name() {
        return company_name;
    }

    public String getOrdered() {
        return ordered;
    }

    public String getDescription() {
        return description;
    }

    public int getStatus() {
        return status;
    }

    public void setId(int id) {
        this.id = id;
    }

    public void setBrand_name(String brand_name) {
        this.brand_name = brand_name;
    }

    public void setCompany_name(String company_name) {
        this.company_name = company_name;
    }

    public void setOrdered(String ordered) {
        this.ordered = ordered;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    @Override
    public String toString() {
        return "Brand{" +
                "id=" + id +
                ", brand_name='" + brand_name + '\'' +
                ", company_name='" + company_name + '\'' +
                ", ordered='" + ordered + '\'' +
                ", description='" + description + '\'' +
                ", status=" + status +
                '}';
    }
}

package com.itheima.mapper;


import com.itheima.pojo.Brand;

import java.util.List;

public interface BrandMapper {
//  查询所有
    public List<Brand> selectAll();

}

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--namespace:名称空间-->
<mapper namespace="com.itheima.mapper.UserMapper">


</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--namespace:名称空间-->
<mapper namespace="com.itheima.mapper.BrandMapper">


    <select id="selectAll" resultType="brand">
        select *
        from tb_brand;

    </select>
</mapper>
public class MybatisTest {
    //测试用例
    @Test
    public void testSelectAll() throws IOException {
        //1.获取SqlSessionFactory//不用写,自己复制
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2.获取SqlSession对象
        SqlSession sqlSession=sqlSessionFactory.openSession();

        //3.获取mapper接口的代理对象
        BrandMapper brandMapper=sqlSession.getMapper(BrandMapper.class);

        //4.执行方法
        List<Brand> brands=brandMapper.selectAll();
        System.out.println(brands);

        //5.释放资源
        sqlSession.close();
        
        //Mybatis完成操作三步,,,编写接口方法,编写sql,执行方法,,,,,,
    }
}

在这里插入图片描述
如果我们Brand里面的名称为brandName
驼峰命名模式,那么就有可能查询不到
但是我们可以取别名

package com.itheima.pojo;

public class Brand {
    private int id ;
    private String brandName  ;
    private String companyName  ;
    private String ordered        ;
    private String description    ;
    private int status       ;

    public int getId() {
        return id;
    }

    public String getbrandName() {
        return brandName;
    }

    public String getcompanyName() {
        return companyName;
    }

    public String getOrdered() {
        return ordered;
    }

    public String getDescription() {
        return description;
    }

    public int getStatus() {
        return status;
    }

    public void setId(int id) {
        this.id = id;
    }

    public void setbrandName(String brandName) {
        this.brandName = brandName;
    }

    public void setcompanyName(String companyName) {
        this.companyName = companyName;
    }

    public void setOrdered(String ordered) {
        this.ordered = ordered;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    @Override
    public String toString() {
        return "Brand{" +
                "id=" + id +
                ", brandName='" + brandName + '\'' +
                ", companyName='" + companyName + '\'' +
                ", ordered='" + ordered + '\'' +
                ", description='" + description + '\'' +
                ", status=" + status +
                '}';
    }
}


比如这样,所有都变成了驼峰模式,但是数据库里面还是下划线的模式
所以找不到

在这里插入图片描述
我们可以用取别名的方法
在sql语句的配置文件那里

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--namespace:名称空间-->
<mapper namespace="com.itheima.mapper.BrandMapper">
<!--数据库表的字段名称和实体类的属性名称不一样,就不能自动封装数据,取别名就可以了-->

        <select id="selectAll" resultType="brand">
            select id ,brand_name as brandName,company_name as companyName,ordered,description,status
            from tb_brand;
        </select>
<!--    <select id="selectAll" resultType="brand">-->
<!--        select *-->
<!--        from tb_brand;-->
<!--    </select>-->
</mapper>

在这里插入图片描述
第一种方法是取别名,让别名和实体类的属性名一样就可以了
第二种方法就是定义sql片段


    <sql id="brand_column">
        id ,brand_name as brandName,company_name as companyName,ordered,description,status
    </sql>

        <select id="selectAll" resultType="brand">
            select
                    <include refid="brand_column" />
            from tb_brand;
        </select>

在这里插入图片描述
缺点就是不灵活,确定了那么多个

接下来用resultMap

    <resultMap id="brandResultMap" type="brand">
        <result column="brand_name" property="brandName"/>
        <result column="company_name" property="companyName"/>
    </resultMap>

            <select id="selectAll" resultMap="brandResultMap">
                select
                        *
                from tb_brand;
            </select>

brandResultMap随便取,是一个唯一标识
brand是类型,也就是别名com.itheima.pojo.Brand的,映射的类型,支持别名
result 是一般字段的映射
id column中id是对主键的映射
companyName是一般字段
column是表的列名
property实体类的属性名
1.定义标签
2.属性替换
在这里插入图片描述

5.2 查看详情

根据id查询详情
在这里插入图片描述

public interface BrandMapper {
//  查询所有
    public List<Brand> selectAll();
    
    //查看详情
    Brand selectByIdBrand(int id);

}
    <select id="selectByIdBrand" resultMap="brandResultMap">
        select *
        from tb_brand where id=#{id};
    </select>

select id中的id和方法名是一样的
#{id}这个就相当于原来写的问号是一样的
{}里面的和方法的参数名称保持一致就可以了

    @Test
    public void testSelectById() throws IOException {
        //1.获取SqlSessionFactory//不用写,自己复制
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2.获取SqlSession对象
        SqlSession sqlSession=sqlSessionFactory.openSession();

        //3.获取mapper接口的代理对象
        BrandMapper brandMapper=sqlSession.getMapper(BrandMapper.class);

        //4.执行方法
        int id=1;
        Brand brand=brandMapper.selectById(id);
        System.out.println(brand);

        //5.释放资源
        sqlSession.close();

        //Mybatis完成操作三步,,,编写接口方法,编写sql,执行方法,,,,,,
    }
}

相比原来只需要改两行代码就可以了
而且这种测试方法,鼠标放在哪里,就运行哪个方法

在这里插入图片描述
#{id}就是?
这个就是参数占位符
参数占位符:
${}
#{}

    <select id="selectById" resultMap="brandResultMap">
        select *
        from tb_brand where id=${id};
    </select>

#{}替换为?,再给?赋值,,这个是为了防止SQL注入的
${}:直接替换为1,直接拼sql,存在SQL注入问题
所以用#{}

    <select id="selectById" resultMap="brandResultMap">
        select *
        from ${tableName} where id=#{id};
    </select>

${}用于表名和列名不固定的情况下
但还是存在SQL注入

    <select id="selectById" parameterType="int" resultMap="brandResultMap">
        select *
        from tb_brand where id=#{id};
    </select>

表示给#{id}设置为int类型
可以省略掉
因为接口那里就已经是int类型的了
在这里插入图片描述
在这里插入图片描述
因为<和插面的<冲突了
所以特殊字符的处理就是转义或者CDATA区

    <select id="selectById"  resultMap="brandResultMap">
        select *
        from tb_brand where id &lt;  #{id};
    </select>

<这个就是<的转义

    <select id="selectById"  resultMap="brandResultMap">
        select *
        from tb_brand where id
        <![CDATA[
        <
        ]]>
        #{id};
    </select>

CDATA区直接CD然后提示就可以了

5.3 条件查询

select * from tb_brand where
就是输入多个条件,然后来查询
状态status=?
company_name=
写一个包含关键字的就可以查询,按理说
company_name like ?
这个是模糊查询
brand_name like ?
如何连接—》and

在这里插入图片描述
@Param(“status”)的意思就是int status中status就是要传递给占位符为status的,就是#{status}

第二个函数的意思就是,把这三个参数封装成一个对象,根据里面的getstatus方法,把对象里面的status,给status

所以参数的占位符名称要和brand对象里面的属性名称一样
不然找不到get方法

第三个就是封装成map集合
map集合键的名称要和参数占位符保持一致

<!--    条件查询-->
    <select id="selectByCondition"  resultMap="brandResultMap">
        select *
        from tb_brand
        where 
            status = #{status}
        and company_name like #{companyName}
        and brand_name like #{brandName}
    </select>

条件查询
1.散装参数 如果有多个参数,需要使用@Param(占位符名称),因为这样可以标记,特定去使用对应的sql语句的占位符
2.对象参数
3.map集合参数

 List<Brand> selectByCondition(@Param("status")int status,@Param("companyName")String companyName,@Param("brandName")String brandName);
@Test
public void testSelectByCondition() throws IOException {
    //1.获取SqlSessionFactory//不用写,自己复制
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

    //2.获取SqlSession对象
    SqlSession sqlSession = sqlSessionFactory.openSession();

    //3.获取mapper接口的代理对象
    BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);

    //4.执行方法
    int status=1;
    String companyName="华为";
    String brandName="华为";//这样是不行的,因为期待的是,用户输入了华为,就进行模糊匹配,所以要写模糊的表达式,用%或者_,在程序里面处理
    companyName="%"+companyName+"%";
    brandName="%"+brandName+"%";

    List<Brand> brands=brandMapper.selectByCondition(status,brandName,companyName);
    System.out.println(brands);


    //5.释放资源
    sqlSession.close();

    }

在这里插入图片描述

    List<Brand> selectByCondition(Brand brand);

@Test
public void testSelectByCondition() throws IOException {
    //1.获取SqlSessionFactory//不用写,自己复制
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

    //2.获取SqlSession对象
    SqlSession sqlSession = sqlSessionFactory.openSession();

    //3.获取mapper接口的代理对象
    BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);

    //4.执行方法
    int status=1;
    String companyName="华为";
    String brandName="华为";//这样是不行的,因为期待的是,用户输入了华为,就进行模糊匹配,所以要写模糊的表达式,用%或者_,在程序里面处理
    companyName="%"+companyName+"%";
    brandName="%"+brandName+"%";

    Brand brand=new Brand();
    brand.setStatus(status);
    brand.setbrandName(brandName);
    brand.setcompanyName(companyName);

    List<Brand> brands=brandMapper.selectByCondition(brand);
    System.out.println(brands);


    //5.释放资源
    sqlSession.close();

    }

在这里插入图片描述

    List<Brand> selectByCondition(Map map);
@Test
public void testSelectByCondition() throws IOException {
    //1.获取SqlSessionFactory//不用写,自己复制
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

    //2.获取SqlSession对象
    SqlSession sqlSession = sqlSessionFactory.openSession();

    //3.获取mapper接口的代理对象
    BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);

    //4.执行方法
    int status=1;
    String companyName="华为";
    String brandName="华为";//这样是不行的,因为期待的是,用户输入了华为,就进行模糊匹配,所以要写模糊的表达式,用%或者_,在程序里面处理
    companyName="%"+companyName+"%";
    brandName="%"+brandName+"%";

//    Brand brand=new Brand();
//    brand.setStatus(status);
//    brand.setbrandName(brandName);
//    brand.setcompanyName(companyName);

    Map  map=new HashMap();
    map.put("status",status);//保证map键的名称和参数占位符的名称一样
    map.put("companyName",companyName);
    map.put("brandName",brandName);

    //List<Brand> brands=brandMapper.selectByCondition(brand);
    List<Brand> brands=brandMapper.selectByCondition(map);
    System.out.println(brands);


    //5.释放资源
    sqlSession.close();

    }

在这里插入图片描述

如果只想查询一个,我们只设置一个

    Map  map=new HashMap();
    map.put("status",status);//保证map键的名称和参数占位符的名称一样
//    map.put("companyName",companyName);
//    map.put("brandName",brandName);

在这里插入图片描述
那么就会查不出来
因为我们的sql语句查的是三个,有两个的值都没有设置,都是null,所以数据查不出来了,所以不灵活
所以如何动态查询呢

就是sql语句会随着用户的输入或者外部条件的变化而变化,我们称之为动态sql
如何判断用户输入没有呢,如果用户输入了,就不是null,就查询
所以这样来 if(status!=null)status=#{status}
这就是动态sql
mybatis很支持动态sql
它有很多标签支持

在这里插入图片描述

<!--    动态条件查询-->
    <select id="selectByCondition"  resultMap="brandResultMap">
        select *
        from tb_brand
        where
        <if test="status !=null">
            status = #{status}
        </if>

<!--        test里面的companyName就是 #{companyName}里面的companyName-->
        <if test="companyName!=null and companyName!='' ">
            and company_name like #{companyName}
        </if>

        <if test="brandName!=null and brandName!=''">
            and brand_name like #{brandName}
        </if>
    </select>
    Map  map=new HashMap();
    map.put("status",status);//保证map键的名称和参数占位符的名称一样
    map.put("companyName",companyName);
    map.put("brandName",brandName);

在这里插入图片描述

    Map  map=new HashMap();
    map.put("status",status);//保证map键的名称和参数占位符的名称一样
    map.put("companyName",companyName);
//    map.put("brandName",brandName);

在这里插入图片描述

    Map  map=new HashMap();
//    map.put("status",status);//保证map键的名称和参数占位符的名称一样
    map.put("companyName",companyName);
//    map.put("brandName",brandName);

在这里插入图片描述
但是这样就会报错
因为第一个status没了,导致sql语句的where后面直接接上了and,所以出错了,sql语法有错
处理方法就是每个if都加and,然后where后面有缓冲,就是有一个恒等式

<!--    动态条件查询-->
    <select id="selectByCondition"  resultMap="brandResultMap">
        select *
        from tb_brand
        where 1=1
        <if test="status !=null">
           and status = #{status}
        </if>

<!--        test里面的companyName就是 #{companyName}里面的companyName-->
        <if test="companyName!=null and companyName!='' ">
            and company_name like #{companyName}
        </if>

        <if test="brandName!=null and brandName!=''">
            and brand_name like #{brandName}
        </if>
    </select>

看这个1=1,其实一点用都没有,就是为了满足语法而已

    Map  map=new HashMap();
//    map.put("status",status);//保证map键的名称和参数占位符的名称一样
    map.put("companyName",companyName);
//    map.put("brandName",brandName);

在这里插入图片描述
但这个方法mbatis早就想好了,可以用where标签来替换where关键字

    <select id="selectByCondition"  resultMap="brandResultMap">
        select *
        from tb_brand
        <where>
            <if test="status !=null">
                and status = #{status}
            </if>

            <!--        test里面的companyName就是 #{companyName}里面的companyName-->
            <if test="companyName!=null and companyName!='' ">
                and company_name like #{companyName}
            </if>

            <if test="brandName!=null and brandName!=''">
                and brand_name like #{brandName}
            </if>
        </where>
        
    </select>

在这里插入图片描述
用where关键字的时候,如果里面只有一个条件,那么就会自动取消and,这就是它的作用

5.4 单条件动态查询

就是用户自己选择条件查询,只针对某一个条件查询,针对这个条件输入自己的关键字

在这里插入图片描述
在这里插入图片描述
这里choose就相当于switch
when就是case
otherwise就是default

    //单条件动态查询
    List<Brand> selectByConditionSingle(Brand brand);//brand对象的作用就是哪个属性有值的话,就用哪个
    </select>
    <select id="selectByConditionSingle" resultMap="brandResultMap">
        select *
        from tb_brand
        where
        <choose>
            <when test="status!=null">
                status=#{status}
            </when>
            <when test="companyName!=null and companyName!=''">
                company_name like #{companyName}
            </when>
            <when test="brandName!=null and brandName!=''">
                brand_name like #{brandName}
            </when>
        </choose>
    </select>
    @Test
    public void testSelectByConditionSingle() throws IOException {
        //1.获取SqlSessionFactory//不用写,自己复制
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2.获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //3.获取mapper接口的代理对象
        BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);

        //4.执行方法
        int status=1;
        String companyName="华为";
        String brandName="华为";//这样是不行的,因为期待的是,用户输入了华为,就进行模糊匹配,所以要写模糊的表达式,用%或者_,在程序里面处理
        companyName="%"+companyName+"%";
        brandName="%"+brandName+"%";

    Brand brand=new Brand();
    brand.setStatus(status);
   // brand.setbrandName(brandName);
    //brand.setcompanyName(companyName);



        //List<Brand> brands=brandMapper.selectByCondition(brand);
        List<Brand> brands=brandMapper.selectByConditionSingle(brand);
        System.out.println(brands);


        //5.释放资源
        sqlSession.close();

    }
    Brand brand=new Brand();
    brand.setStatus(status);
   // brand.setbrandName(brandName);
    //brand.setcompanyName(companyName);

在这里插入图片描述
但万一用户一个都不选呢


    Brand brand=new Brand();
   // brand.setStatus(status);
   // brand.setbrandName(brandName);
    //brand.setcompanyName(companyName);

这样就可能会出错,因为一个都没选的话,where后面就没有内容了
所以用default

    </select>
    <select id="selectByConditionSingle" resultMap="brandResultMap">
        select *
        from tb_brand
        where
        <choose>
            <when test="status!=null">
                status=#{status}
            </when>
            <when test="companyName!=null and companyName!=''">
                company_name like #{companyName}
            </when>
            <when test="brandName!=null and brandName!=''">
                brand_name like #{brandName}
            </when>
            <otherwise>
                1=1
            </otherwise>
        </choose>
    </select>

这里where1=1,单纯是为了满足语法

也可以这样

    <select id="selectByConditionSingle" resultMap="brandResultMap">
        select *
        from tb_brand
        <where>
            <choose>
                <when test="status!=null">
                    status=#{status}
                </when>
                <when test="companyName!=null and companyName!=''">
                    company_name like #{companyName}
                </when>
                <when test="brandName!=null and brandName!=''">
                    brand_name like #{brandName}
                </when>
            </choose>
        </where>
    </select>

用where标签,和上面就是一模一样的了

5.5 添加

在这里插入图片描述

    //添加
    void add(Brand brand);

这里更改一下,status是int类型

    <insert id="add">
        insert into tb_brand(brand_name,company_name,ordered,description,status)
        values(#{brandName},#{companyName},#{ordered},#{description},#{status})
    </insert>
    @Test
    public void testAdd() throws IOException {
        //1.获取SqlSessionFactory//不用写,自己复制
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2.获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //3.获取mapper接口的代理对象
        BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);

        //4.执行方法
        int status=1;
        String companyName="波导手机";
        String brandName="波导";
        String description="手机中的战斗机";
        int ordered=100;

        Brand brand=new Brand();
         brand.setStatus(status);
         brand.setbrandName(brandName);
        brand.setcompanyName(companyName);
        brand.setDescription(description);
        brand.setOrdered(ordered);

        brandMapper.add(brand);
        //5.释放资源
        sqlSession.close();
    }

在这里插入图片描述
但是数据库里面并没有添加

为什么呢
因为mybatis给你关闭了事务的自动提交,所以你要手动提交才行

   @Test
    public void testAdd() throws IOException {
        //1.获取SqlSessionFactory//不用写,自己复制
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2.获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //3.获取mapper接口的代理对象
        BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);

        //4.执行方法
        int status=1;
        String companyName="波导手机";
        String brandName="波导";
        String description="手机中的战斗机";
        int ordered=100;

        Brand brand=new Brand();
         brand.setStatus(status);
         brand.setbrandName(brandName);
        brand.setcompanyName(companyName);
        brand.setDescription(description);
        brand.setOrdered(ordered);

        brandMapper.add(brand);
        
        //提交事务
        sqlSession.commit();
        
        //5.释放资源
        sqlSession.close();
    }

在这里插入图片描述
如果不想手动提交事务的话
可以这样

        //2.获取SqlSession对象
        //SqlSession sqlSession = sqlSessionFactory.openSession();
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

true这样就是自动提交了
openSession是默认开启事务的

5.6 主键返回

在这里插入图片描述

        brandMapper.add(brand);
        Integer id=brand.getId();
        System.out.println(id);

注意这里的id应该改为Integer,不然默认为0
这里打印出来就是null
在这里插入图片描述
所以数据库添加成功之后,数据库里面的id值无法获取出来

在这里插入图片描述
但是这里数据里里面是有数据的
但是得不到id
如何把数据库里面的id绑定到对象里面呢

    <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>

我们可以设置一个useGeneratedKeys为true
然后一个keyProperty为order对象里面主键id的名称
设置完这个,对象里面就有id值了

        brandMapper.add(brand);
        Integer id=brand.getId();
        System.out.println(id);

在这里插入图片描述
这就是主键返回

5.7 修改全部字段

在这里插入图片描述
就是点击编辑按钮的时候,然后就可以对所有的数据更改

    <update id="update">
        update tb_brand
        set 
            brand_name=#{brandName},
            company_name=#{companyName},
            ordered=#{ordered},
            description=#{description},
            status=#{status}
        where id=#{id};
    </update>
    int update(Brand brand);
    @Test
    public void testUpdate() throws IOException {
        //1.获取SqlSessionFactory//不用写,自己复制
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2.获取SqlSession对象
        //SqlSession sqlSession = sqlSessionFactory.openSession();
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

        //3.获取mapper接口的代理对象
        BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);

        //4.执行方法
        int id=5;//修改第五个
        int status=1;
        String companyName="波导手机";
        String brandName="波导";
        String description="波导手机,手机中的战斗机";
        int ordered=200;

        Brand brand=new Brand();
        brand.setStatus(status);
        brand.setbrandName(brandName);
        brand.setcompanyName(companyName);
        brand.setDescription(description);
        brand.setOrdered(ordered);
        brand.setId(id);

        int count=brandMapper.update(brand);
        System.out.println(count);

        //提交事务
        sqlSession.commit();

        //5.释放资源
        sqlSession.close();
    }

在这里插入图片描述
在这里插入图片描述

5.8 修改动态字段

在这里插入图片描述
意思是有很多的数据,只定向的修改几个就可以了
比如修改密码,那么就只提交密码和id就可以了
如果用原来的sql语句,只提交了几个,那么其他几个就变成null了

        Brand brand=new Brand();
        Brand brand=new Brand();
        brand.setStatus(status);
//        brand.setbrandName(brandName);
//        brand.setcompanyName(companyName);
//        brand.setDescription(description);
//        brand.setOrdered(ordered);
        brand.setId(id);

我们看这个,只提交id和status
在这里插入图片描述
在这里插入图片描述

    <update id="update">
        update tb_brand
        set
            <if test="brandName!=null and brandName!=''">
                brand_name=#{brandName},
            </if>
            <if test="companyName!=null and companyName!=''">
                company_name=#{companyName},
            </if>
    <!--        因为ordered是Integer,所以不会为空字符串,只会为null-->
            <if test="ordered!=null">
                ordered=#{ordered},
            </if>
            <if test="description!=null">
                description=#{description},
            </if>
            <if test="status!=null">
                status=#{status}
            </if>
        where id=#{id};
    </update>

这个有一点问题,第一个就是逗号的问题,如果最后一句没有执行,那么where前面就会有一个逗号
第二个就是如果全部if都没有执行,那么只有set了
这两个问题可以用set标签

    <update id="update">
        update tb_brand
        <set>
            <if test="brandName!=null and brandName!=''">
                brand_name=#{brandName},
            </if>
            <if test="companyName!=null and companyName!=''">
                company_name=#{companyName},
            </if>
            <!--        因为ordered是Integer,所以不会为空字符串,只会为null-->
            <if test="ordered!=null">
                ordered=#{ordered},
            </if>
            <if test="description!=null">
                description=#{description},
            </if>
            <if test="status!=null">
                status=#{status}
            </if>
        </set>

        where id=#{id};
    </update>
        //4.执行方法
        int id=6;//修改第五个
        int status=0;
        String companyName="波导手机";
        String brandName="波导";
        String description="波导手机,手机中的战斗机";
        int ordered=200;

        Brand brand=new Brand();
        brand.setStatus(status);
//        brand.setbrandName(brandName);
//        brand.setcompanyName(companyName);
//        brand.setDescription(description);
//        brand.setOrdered(ordered);
        brand.setId(id);

在这里插入图片描述

5.9 删除功能

在这里插入图片描述
根据id把数据删除掉

    //根据id删除
    void deleteById(int id);
    <delete id="deleteById">
        delete from tb_brand where id=#{id};
    </delete>
    @Test
    public void testDeleteById() throws IOException {
        //1.获取SqlSessionFactory//不用写,自己复制
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2.获取SqlSession对象
        //SqlSession sqlSession = sqlSessionFactory.openSession();
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

        //3.获取mapper接口的代理对象
        BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);

        //4.执行方法
        int id=6;//修改第五个

        brandMapper.deleteById(id);


        //提交事务
        sqlSession.commit();

        //5.释放资源
        sqlSession.close();
    }

在这里插入图片描述

5.10 批量删除

就是直接删除多个数据
就是选中多个,然后一起删除,这就是复选框

就是给的多个id删除,分装成id数组,传进去就可以了
在这里插入图片描述
但是?占位符应该写几个呢,所以应该是动态sql,要有几个id,所以要遍历这个数组,用foreach
collection表示你要遍历哪个数组
item就是遍历出来的每一个元素
#{id}为占位符
那么遍历几次,就有几个?
这样就可以了

    //批量删除
    void deleteByIds(int[]ids);
    <delete id="deleteByIds">
        delete from tb_brand where id
        in (?,?,?);
    </delete>

按理说应该这样写,写很多个问号,但是有几个?呢,遍历一下就知道了

    <delete id="deleteByIds">
        delete from tb_brand where id
        in (
            <foreach collection="ids"></foreach>
        );
    </delete>

但这里不能直接写ids,因为mybatis会将数组参数分装成一个Map集合
默认:key的名称是array,val就是这个数组
所以我们要array来获取数组

    <delete id="deleteByIds">
        delete from tb_brand where id
        in (
            <foreach collection="array"></foreach>
        );
    </delete>

或者也可以这样,用@Param来改变map集合默认key的名称

    //批量删除
    void deleteByIds(@Param("ids") int[]ids);
    <delete id="deleteByIds">
        delete from tb_brand where id
        in (
            <foreach collection="ids"item="id">
                #{id}
            </foreach>
        );
    </delete>

如果数组里面有三个id,那么就会生成三个#{id},那么就会被替换成?
而且之间应该有逗号隔开

    <delete id="deleteByIds">
        delete from tb_brand where id
        in (
            <foreach collection="ids" item="id" separator=",">
                #{id}
            </foreach>
        );
    </delete>

separator就是分隔符的意思,我们用逗号分隔开

        //4.执行方法
        int[] ids={5,7,8};

        brandMapper.deleteByIds(ids);

在这里插入图片描述

    <delete id="deleteByIds">
        delete from tb_brand where id
        in 
            <foreach collection="ids" item="id" separator="," open="(" close=")">
                #{id}
            </foreach>
        ;
    </delete>

这样写的话,in就不用写括号了
下面演示一下array

    //批量删除
    void deleteByIds(int[]ids);
    <delete id="deleteByIds">
        delete from tb_brand where id
        in
            <foreach collection="array" item="id" separator="," open="(" close=")">
                #{id}
            </foreach>
        ;
    </delete>

这样写也是可以的

没写@,就不要写ids
反正就这两种方法

5.11 参数传递

在这里插入图片描述
传了多个参数,那么就要用@Param
要和参数的占位符名称一样

如果为多个参数的话,会分装为map集合
把这些参数一个一个装到map里面
值就是参数名
键就是这样的
map.put(“arg0”,参数值1)
map.put(“param1”,参数值1)
map.put(“arg1”,参数值2)
map.put(“param2”,参数值2)

 List<Brand> selectByCondition(@Param("status")int status,@Param("companyName")String companyName,@Param("brandName")String brandName);
    List<Brand> brands=brandMapper.selectByCondition(status,companyName,brandName);
    System.out.println(brands);
    List<Brand> selectByCondition(int status,String companyName,String brandName);

如果去掉@Param就会出错
在这里插入图片描述
他说我们可以用[arg2, arg1, arg0, param3, param1, param2]

    <select id="selectByCondition"  resultMap="brandResultMap">
        select *
        from tb_brand
        <where>
            <if test="status !=null">
                and status = #{status}
            </if>

            <!--        test里面的companyName就是 #{companyName}里面的companyName-->
            <if test="companyName!=null and companyName!='' ">
                and company_name like #{companyName}
            </if>

            <if test="brandName!=null and brandName!=''">
                and brand_name like #{brandName}
            </if>
        </where>

    </select>

改为

    <select id="selectByCondition"  resultMap="brandResultMap">
        select *
        from tb_brand
        <where>
            <if test="arg0 !=null">
                and status = #{arg0}
            </if>

            <!--        test里面的companyName就是 #{companyName}里面的companyName-->
            <if test="arg1!=null and arg1!='' ">
                and company_name like #{arg1}
            </if>

            <if test="arg2!=null and arg2!=''">
                and brand_name like #{arg2}
            </if>
        </where>

    </select>

在这里插入图片描述
然后就是parame1,也是可以的这些

    <select id="selectByCondition"  resultMap="brandResultMap">
        select *
        from tb_brand
        <where>
            <if test="param1 !=null">
                and status = #{param1}
            </if>

            <!--        test里面的companyName就是 #{companyName}里面的companyName-->
            <if test="param2!=null and param2!='' ">
                and company_name like #{param2}
            </if>

            <if test="param3!=null and param3!=''">
                and brand_name like #{param3}
            </if>
        </where>

    </select>

在这里插入图片描述
但是并不推荐上面两种方法,还是建议使用@Param,这个就是来替换arg0,agr1,只对第一个参数@Param,那么arg0就被替换了,而且不能使用了,以此类推

单个参数的话,如果是POJO类型,可以直接使用,属性名和参数占位符一样,不用@Param
Map集合键名和参数占位符一样就可以了,直接使用,,不用@Param
其他类型:比如定义一个intid类型,也可以直接用

Collection:建立一个map,键就是collection,值就是你传进来的
还有一个键是arg0
List也是一样的,map有三个键,Collection,arg0,list
数组的话,键就是array和arg0

但是只要你全部用@Param(修改arg0),就没有事了

5.12 注解完成增删改查

在这里插入图片描述
就是把sql语句写在注解中,而不是配置文件

意思就是方法和sql语句挨在一起了
有四个注解
但是一般只完成简单功能,复杂功能还是用配置文件
比如动态sql还是写在配置文件中好点

    User selectById(int id);

用这个的注解的前提就是相关的配置要注释掉


<!--  resultType是别名,大小写无所谓  -->
<!--    <select id="selectById" resultType="User">-->
<!--        select * from tb_user where id =#{id};-->
<!--    </select>-->
    @Select("select * from tb_user where id = #{id}")
    User selectById(int id);
        User users=userMapper.selectById(3);
        System.out.println(users);

在这里插入图片描述

总结

;