Mybaits

Mybatis与JDBC的对比

快速入门


有些步骤的代码就是从这copy的

https://mybatis.org/mybatis-3/zh/getting-started.html

1.创建user表

DROP TABLE IF EXISTS `tb_user`;
CREATE TABLE `tb_user`  (
  `id` int NOT NULL,
  `username` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
  `password` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
  `gender` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
  `addr` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `tb_user` VALUES (1, 'admin', '123456', '男', '北京');
INSERT INTO `tb_user` VALUES (2, 'Benson', '666666', '男', '广东');
INSERT INTO `tb_user` VALUES (3, 'Lucy', '888888', '女', '上海');

SET FOREIGN_KEY_CHECKS = 1;

2.导入maven依赖

<dependencies>
        <dependency><!--mysql依赖-->
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>

        <dependency><!--mybatis依赖-->
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.3</version>
        </dependency>

        <dependency><!--单元测试-->
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.20</version>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.2.3</version>
        </dependency>
    </dependencies>

将logback.xml粘贴到main的resources

<?xml version="1.0" encoding="UTF-8"?>

<!-- 配置文件修改时重新加载,默认true -->
<configuration scan="true">
    
    <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
    <property name="CATALINA_BASE" value="**/logs"></property>
    
    <!-- 控制台输出 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder charset="UTF-8">
            <!-- 输出日志记录格式 -->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
 
    <!-- 第一个文件输出,每天产生一个文件 -->
    <appender name="FILE1" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 输出文件路径+文件名 -->
            <fileNamePattern>${CATALINA_BASE}/aa.%d{yyyyMMdd}.log</fileNamePattern>
            <!-- 保存30天的日志 -->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder charset="UTF-8">
            <!-- 输出日志记录格式 -->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
 
    <!-- 第二个文件输出,每天产生一个文件 -->
    <appender name="FILE2" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${CATALINA_BASE}/bb.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${CATALINA_BASE}/bb.%d{yyyyMMdd}.log</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder charset="UTF-8">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    
    <appender name="CUSTOM" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${CATALINA_BASE}/custom.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- daily rollover -->
            <fileNamePattern>${CATALINA_BASE}/custom.%d{yyyy-MM-dd}.log</fileNamePattern>
            <!-- keep 30 days' worth of history -->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder charset="UTF-8">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    
    <!-- 设置日志输出级别 -->
    <root level="ERROR">
        <appender-ref ref="CONSOLE" />
    </root>
    <logger name="file1" level="DEBUG">
        <appender-ref ref="FILE1" />
    </logger>
    <logger name="file1" level="INFO">
        <appender-ref ref="FILE2" />
    </logger>
    <!-- 自定义logger -->
    <logger name="custom" level="INFO">
        <appender-ref ref="CUSTOM" />
    </logger>
</configuration>

编写mybatis核心配置文件

在main的resources下新建mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <!--数据库连接信息-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///test"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers><!--加载sql映射文件路径-->
        <mapper resource="UserMapper.xml"/>
    </mappers>
</configuration>

新建pojo包下的User类

package com.benson.pojo;

public class User {
    private Integer id;
    private String username;
    private String password;
    private String gender;
    private String addr;

    public Integer getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", gender='" + gender + '\'' +
                ", addr='" + addr + '\'' +
                '}';
    }
}

编码sql映射文件

统一管理sql语句

在main的resources新建对应sql映射的配置文件
UserMapper.xml

<?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:名称空间,相当于包,用来区分同名id的-->
<mapper namespace="test">
    <select id="selectAll" resultType="com.benson.pojo.User">
        <!--id是指向sql的唯一标识,resultType是返回结果的类型-->
        select * from tb_user;
    </select>
</mapper>

编码

在pojo包同级新建测试类MybatisDemo.java

package com.benson;

import com.benson.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class MybatisDemo {
    public static void main(String[] args) throws IOException {
        //1.加载Mybatis核心配置文件,获取SqlSessionFactory对象
        String resource = "mybatis-config.xml";//核心配置文件路径
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2.获取SqlSession对象,它能执行sql语句
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //3.执行sql
        List<User> users = sqlSession.selectList("test.selectAll");
        //根据UserMapper的test名称空间的idselectAll来执行对应的语句
        System.out.println(users);

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

总结

Mybatis就是把数据库的连接信息和sql语句分别写到mybatis-config.xml、UserMapper.xml配置文件中,将共性提取出来到配置中,java类里如MybatisDemo.java写的都是基本不变的业务逻辑。

后期维护时一些信息如数据库密码、sql语句要改变,就到配置中改,不需要动业务逻辑。

Mapper代理开发


sqlSession的方法还存在硬编码的问题,selectList方法的参数是写死的
用Mapper代理就能解决这个问题

Mapper代理开发的规则

创建Mapper接口

新建mapper包并新建Mapper接口

然后在resources下新建目录,名字不能用.而是/来分隔,这样才有层次结构

注意名字要相同,然后把UserMapper.xml移动到该包里面去,同时改下mybatis-config.xml中UserMapper的路径

配置sql映射文件

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

以前是随便写的,现在要改成对应的目录了

Mapper接口定义方法

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

编码

MybatisDemo.java

package com.benson;

import com.benson.mapper.UserMapper;
import com.benson.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class MybatisDemo {
    public static void main(String[] args) throws IOException {
        //1.加载Mybatis核心配置文件,获取SqlSessionFactory对象
        String resource = "mybatis-config.xml";//核心配置文件路径
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2.获取SqlSession对象,它能执行sql语句
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //3.获取UserMapper接口的代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> users = userMapper.selectAll();
        System.out.println(users);
        //4.释放资源
        sqlSession.close();
    }
}

拓展


如果Mapper接口名称和sql文件名称相同

并在同一目录下,编译后可视作在同一目录下
就能简化mybatis-config.xml中加载sql映射文件的语句
当有很多sql映射文件(如StudentMapper、TeacherMapper)时就不用一句句地写
直接通过扫描包来加载

简单来说,只要按照上述的3个规范进行Mapper代理开发,都能用这种方式加载。

Mybatis核心配置文件

environments

该标签下可以用多个environment标签(id来区分),用来配置多个数据库信息,通过default切换当前数据库
如图开发和生产采用两个数据库,让当前数据库切换为开发时用的数据库(id为test)
当然开发库那里应该和生产库信息不一样,图中是因为教学举例而没改

transactionManager

事务的管理方式,下图采用的是jdbc的方式

不过无需深入mybatis的事务管理,后面开发会用Spring接管事务

dataSource


用来管理数据库连接的

mappers

映射器

typeAliases

类型别名,用来降低配置文件中参数的冗余度

在mybatis-config.xml中加入这段语句,在类型别名标签中扫描itheima.pojo这个包
相当于给pojo包下的所有实体类起了别名,别名默认是User且不区分大小写
所以可以在对应sql映射文件UserMapper.xml中简化名称的书写

标签顺序


一定要按照如图的顺序编写便签,如mappers在同级中一定要放在最后

typeAliases在mappers后面就报错了

使用Mybatis实现增删改查

有两种方式:配置文件&注解
先以配置文件为例

准备环境

1.创建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),
    status int
);

insert into tb_brand(
brand_name, company_name, ordered, description, status)
values ('华为','华为公司',1,'中华有为',1),
       ('小米','小米公司',2,'areyouok',1),
       ('vivo','vivo公司',3,'中华有为',1);

select * from tb_brand;


2.Brand.java

package com.benson.pojo;

public class Brand {
    private Integer id;
    private String brandName;
    private String companyName;
    private Integer ordered;
    private String description;
    private Integer status;//0:禁用 1:启用
    /*基本类型建议换成包装类,因为基本类型的默认值可能不适应需求
    比如int的默认值是0,对于ordered和status而言不适合
    而Integer的默认值是null,相比之下更合适些
    */

    public Integer getId() {
        return id;
    }

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

    public String getBrandName() {
        return brandName;
    }

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

    public String getCompanyName() {
        return companyName;
    }

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

    public Integer getOrdered() {
        return ordered;
    }

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

    public String getDescription() {
        return description;
    }

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

    public Integer getStatus() {
        return status;
    }

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

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

3.MybatisX插件
能够快速在Mapper配置的sql和对应接口的方法之间跳转,加快找代码的效率

查询

查询所有


mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <!--数据库连接信息-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///test"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers><!--加载sql映射文件路径-->
        <mapper resource="com\benson\mapper\BrandMapper.xml"/>
    </mappers>
</configuration>

BrandMapper.xml

<?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:名称空间,相当于包,用来区分同名id的-->
<mapper namespace="com.benson.mapper.BrandMapper">
    <select id="selectAll" resultType="com.benson.pojo.Brand">
        <!--id是指向sql的唯一标识,resultType是返回结果的类型-->
        select * from tb_brand;
    </select>
</mapper>

Test.java

package com.benson;

import com.benson.mapper.BrandMapper;
import com.benson.pojo.Brand;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class Test {
    public static void main(String[] args) throws IOException {
        //1.加载Mybatis核心配置文件,获取SqlSessionFactory对象
        String resource = "mybatis-config.xml";//核心配置文件路径
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2.获取SqlSession对象,它能执行sql语句
        SqlSession sqlSession = sqlSessionFactory.openSession();

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

        //4.执行方法
        List<Brand> brands = brandMapper.selectAll();
        System.out.println(brands);
        //4.释放资源
        sqlSession.close();
    }
}


商品名和公司名都是null,因为Brand定义的属性brandName和数据库字段brand_name不一致

  • 1.把Brand实体类属性改成跟数据库一样,brand_name。但不适合项目开发,因为前后端很可能不是同一个人写的
  • 2.sql语句起别名

    但这样做每个查询的sql都要起一次别名很麻烦,所以可以用sql片段来提取要查询的字段,用到再导入

    但如果查询的字段有所改变又要写一个sql片段,这种方法也不够简便

resultMap


BrandMapper.xml

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

<mapper namespace="com.benson.mapper.BrandMapper">
    <!--id随便写,type是和哪个类映射-->
    <resultMap id="brandResultMap" type="com.benson.pojo.Brand">
        <result column="brand_name" property="brandName" />
        <!--
        id标签是对主键字段作映射的,result标签是映射普通字段的
        这里要映射的都是普通字段,所以用result标签
        让数据库的字段名和实体类的属性名作映射,一一对应-->
        <result column="company_name" property="companyName" />
    </resultMap>

    <select id="selectAll" resultMap="brandResultMap">
        <!--id是指向sql的唯一标识,resultType是返回结果的类型-->
        <!--resultMap替换掉resultType-->
        select * from tb_brand;
    </select>
</mapper>

条件查询

单条件查询


特殊字符处理

多条件查询


BrandMapper.xml

BrandMapper.java

Test.java

动态条件查询

用户查询时不一定会把所有条件都输入,更多是输入一个条件,比如只输入商品名,这时也要返回符合的结果。

多条件查询是用and连接条件的,所以条件不输全就得不到结果。要解决这种需求,就要用到动态条件查询。

用if判断用户是否在对应的条件填写了信息

mybatis提供了更好的方法

单条件动态查询


Test.java

BrandMapper.xml

不写otherwise,用where标签包裹更简便,where标签十分灵活,同样能解决条件为空时不报错
条件值为空时,where标签会把where关键字也去掉

添加



但仅仅这样无法添加成功,因为mybatis默认是手动提交事务的,代码里没有写提交事务。
有两种方式

再执行一次

主键返回


添加成功后是获取不到主键id的值的

修改

修改全部


修改动态字段


修改部分字段时,比如修改密码,只会修改密码字段的值,就用到动态sql了

删除

根据id删除



批量删除



如果嫌in括号一上一下不好看,可以用标签来美化
open和close分别是foreach标签开头和结尾的位置

单例测试

maven项目有main和test两个大的目录,一个是放生产环境源码的,一个是开发时用来测试的
开发时的测试类可以写在test的java目录下

同时测试类里可以使用@Test来使方法单独使用,不需要在psvm中调用来使用方法

目的是方便测试不同的方法,开发中往往会写很多个方法,在psvm中调用又比较麻烦
就可以用@Test

每个绿色按钮对应各自的方法

参数传递



参数类型是Collection、List、Array和多个参数,mybatis会封装成Map集合
共同点是会根据参数的先后用arg0、arg1、arg2这样的顺序标记对应的参数,值都是对应的数据
不同点是会额外根据参数的类型用对应类型的键作标记

  • 多个参数
    如在接口中的方法List<Brand> select(String username,String password)
    username对应的key的arg0,password对应的key的arg1
    多个参数额外的key是param,所以username还有一个key,param1。password还有一个key,param2。
    在sql映射中可以用key来表示username和password的参数占位符

  • Array
    如void deleteByIds(int[] ids);
    参数类型为数组,对应的key有arg0和array,所以能用#{arg0}或者#{array}来传参

其他两种类型同理

总结

对于方法中参数类型是Collection、List、Array和有多个参数的情况,通通使用@Param注解
因为能大大提高代码的可阅读性

源码


Brand.java

package com.benson.pojo;

public class Brand {
    private Integer id;
    private String brandName;
    private String companyName;
    private Integer ordered;
    private String description;
    private Integer status;//0:禁用 1:启用
    /*基本类型建议换成包装类,因为基本类型的默认值可能不适应需求
    比如int的默认值是0,对于ordered和status而言不适合
    而Integer的默认值是null,相比之下更合适些
    */

    public Integer getId() {
        return id;
    }

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

    public String getBrandName() {
        return brandName;
    }

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

    public String getCompanyName() {
        return companyName;
    }

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

    public Integer getOrdered() {
        return ordered;
    }

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

    public String getDescription() {
        return description;
    }

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

    public Integer getStatus() {
        return status;
    }

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

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

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <!--数据库连接信息-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///test"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers><!--加载sql映射文件路径-->
        <mapper resource="com\benson\mapper\BrandMapper.xml"/>
    </mappers>
</configuration>

BrandMapper.xml

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

<mapper namespace="com.benson.mapper.BrandMapper">
    <!--id随便写,type是和哪个类映射-->
    <resultMap id="brandResultMap" type="com.benson.pojo.Brand">
        <result column="brand_name" property="brandName"/>
        <!--
        id标签是对主键字段作映射的,result标签是映射普通字段的
        这里要映射的都是普通字段,所以用result标签
        让数据库的字段名和实体类的属性名作映射,一一对应-->
        <result column="company_name" property="companyName"/>
    </resultMap>

    <!--查询所有-->
    <select id="selectAll" resultMap="brandResultMap">
        <!--id是指向sql的唯一标识,resultType是返回结果的类型-->
        <!--resultMap替换掉resultType-->
        select * from tb_brand;
    </select>

    <!--单条件查询-->
    <select id="selectById" resultMap="brandResultMap">
        select * from tb_brand where id = #{id};
        <!--#{id}是selectById(id)传过来的参数id
        还有${id}这种写法,不过这种写法存在sql注入的风险,适用于列明不固定的时候
        而#{id}能加参数id替换为?规避sql注入
        -->
    </select>

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

    <!--动态条件查询-->
    <select id="selectByConditionDynamic" resultMap="brandResultMap">
        select * from tb_brand
        <where>
            <if test="status != null"><!--如果条件status不为空就赋值-->
                status = #{status}
            </if>
            <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="selectByConditionSingle" resultMap="brandResultMap">
        select * from tb_brand
        <where>
            <choose><!--相当于switch-->
                <when test="status != null"><!--相当于case-->
                    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>

    <!--添加-->
    <insert id="add" useGeneratedKeys="true" keyProperty="id">
        <!--
        useGeneratedKeys="true"返回自增主键id
        keyProperty="id"接收主键id的值-->
        insert into tb_brand(brand_name,company_name,ordered,description,status)
        values(#{brandName},#{companyName},#{ordered},#{description},#{status});
    </insert>

    <!--修改全部-->
    <update id="updateAll">
        update tb_brand
        set
            brand_name = #{brandName},
            company_name = #{companyName},
            ordered = #{ordered},
            description = #{description},
            status = #{status}
        where id = #{id};
    </update>

    <!--修改动态字段-->
    <update id="updateDynamic">
        update tb_brand
        <set><!--跟where标签类似,解决无数据和最后一个数据有逗号的sql语法报错-->
            <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>

    <!--根据id删除-->
    <delete id="deleteById">
        delete from tb_brand where id = #{id};
    </delete>

    <!--批量删除-->
    <delete id="deleteByIds">
        delete from tb_brand where id
        in(
            <!--用foreach来遍历出ids数组的元素item,名为id
            collection="ids"指明ids就是要遍历的数组
            这里如果接口那不用注解标明,是不能写ids的!!!而是array
            因为mybatis默认会将数据参数封装为一个Map集合,key是array,值是数组参数的值
            而使用注解能改变map集合的默认key名称
            separator是分隔符,用,来分隔每个item,保证sql的语法正确
            而且-->
            <foreach collection="ids" item="id" separator=",">
                #{id}
            </foreach>
        );
    </delete>
</mapper>

BrandMapper.java

package com.benson.mapper;

import com.benson.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);
    /*
    * 多条件查询 有3种接收参数的方式
    * 1.散装参数 用注解接收 @Param("sql映射对应的参数占位符名称")
    * @Param("status")的status对应sql映射中status = #{status}的#{status}中的status
    * 2.对象参数:对象的属性名要和参数占位符名称一致
    * 3.集合参数
    * */
    //1.散装参数
//    List<Brand> selectByCondition(@Param("status") int status,
//    @Param("companyName") String companyName,
//    @Param("brandName")String brandName);
    //2.对象参数
//    List<Brand> selectByCondition(Brand brand);
    //3.集合参数
    List<Brand> selectByCondition(Map map);

    //动态条件查询
    List<Brand> selectByConditionDynamic(Map map);

    //单条件动态查询
    List<Brand> selectByConditionSingle(Brand brand);

    //添加
    void add(Brand brand);

    //修改全部
    void updateAll(Brand brand);

    //修改动态字段
    void updateDynamic(Brand brand);

    //根据id删除
    void deleteById(int id);

    //批量删除
    void deleteByIds(@Param("ids") int[] ids);
}

测试类
Test.java

package com.benson;

import com.benson.mapper.BrandMapper;
import com.benson.pojo.Brand;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Test {
    public static void main(String[] args) throws IOException {
        //1.加载Mybatis核心配置文件,获取SqlSessionFactory对象
        String resource = "mybatis-config.xml";//核心配置文件路径
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2.获取SqlSession对象,它能执行sql语句
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

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

        //4.执行方法
        //查询所有
//        List<Brand> brands = brandMapper.selectAll();
//        System.out.println(brands);
        //单条件查询
//        int id = 2;//模拟前端单条件查询的数据
//        Brand brand = brandMapper.selectById(id);
//        System.out.println(brand);
        //多条件查询&单条件动态查询
//        int status = 1;
//        String companyName = "华为";
//        String brandName = "华为";//模拟前端多条件查询的数据
//        //模糊处理数据
//        companyName = "%" + companyName + "%";
//        brandName = "%" + brandName + "%";

        //2.封装对象&单条件动态查询
//        Brand brand = new Brand();
////        brand.setStatus(status);
//        brand.setCompanyName(companyName);
//        brand.setBrandName(brandName);

        //3.集合参数
//        Map map = new HashMap();
////        map.put("status",status);
//        map.put("companyName",companyName);
////        map.put("brandName",brandName);

//        List<Brand> brands = brandMapper.selectByCondition(status, companyName, brandName);//1.散装参数
//        List<Brand> brands = brandMapper.selectByCondition(brand);//2.对象参数
//        List<Brand> brands = brandMapper.selectByCondition(map);//3.集合参数

//        List<Brand> brands = brandMapper.selectByConditionDynamic(map);//动态条件查询

        //单条件动态查询
//        List<Brand> brands = brandMapper.selectByConditionSingle(brand);

//        System.out.println(brands);

        //添加
//        int status = 1;
//        String companyName = "oppo";
//        String brandName = "oppo公司";
//        String description = "前后两千万";
//        int ordered = 5;
//
//        Brand brand = new Brand();
//        brand.setStatus(status);
//        brand.setCompanyName(companyName);
//        brand.setBrandName(brandName);
//        brand.setDescription(description);
//        brand.setOrdered(ordered);
//
//        brandMapper.add(brand);
//        System.out.println(brand.getId());

        //修改所有
//        int status = 0;
//        String companyName = "oppo";
//        String brandName = "oppo公司";
//        String description = "oppo前后像素两千万";
//        int ordered = 15;
//        int id = 12;
//
//        Brand brand = new Brand();
//        brand.setStatus(status);
////        brand.setCompanyName(companyName);
////        brand.setBrandName(brandName);
//        brand.setDescription(description);
////        brand.setOrdered(ordered);
//        brand.setId(id);
//
////        brandMapper.updateAll(brand);
//
//        //修改动态字段
//        brandMapper.updateDynamic(brand);

//        //根据id删除
//        int id = 13;
//        brandMapper.deleteById(id);

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

MybatisTest.java

import com.benson.mapper.BrandMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;

public class MybatisTest {
    @Test
    public void testDeleteByIds() throws IOException{
        //1.加载Mybatis核心配置文件,获取SqlSessionFactory对象
        String resource = "mybatis-config.xml";//核心配置文件路径
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2.获取SqlSession对象,它能执行sql语句
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

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

        //4.执行方法
        int[] ids = {12,14,15};//模拟要删除的几个商品
        brandMapper.deleteByIds(ids);


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

注解开发

跟配置文件开发的区别在于,配置文件开发是把sql写在配置文件里
注解开发是把sql写在注解里

使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java注解不仅力不从心,还会让你本就复杂的sql语句更加混乱不堪。因此,简单的sql用注解,复杂的用xml。

  • 示例
    把xml相关的语句注释掉,然后在BrandMapper.java接口中
    在方法的上面一行用@Select注解写sql
posted @ 2023-02-25 23:20  ben10044  阅读(22)  评论(0编辑  收藏  举报