MyBatis 的基本CRUD操作

MyBatis 基本的 CRUD 操作及配置文件解析


下面介绍基于 xml 映射文件方式实现基本的 CRUD 操作和

Mybatis 的学习 demo 已上传 GitHub,地址:https://github.com/Jacks5320/MybatisStudyDemo


1 数据库表

CREATE DATABASE IF NOT EXISTS `mybatis_study`;

USE `mybatis_study`;

CREATE TABLE IF NOT EXISTS `tb_account`(
  `id` INT(10) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(10) DEFAULT NULL,
  `money` FLOAT(5.2) DEFAULT 0,
  PRIMARY KEY( `id` )
)ENGINE=INNODB DEFAULT CHARSET=utf8;

INSERT INTO `tb_account`(`id`,`name`,`money`) VALUES
(1,'小张',1000.0),
(2,'小李',2000.0),
(3,'小丽',1500.0);

2 实体类

public class Account implements Serializable {
    private Integer id;
    private String accountName;
    private Double nowMoney;
    //  以下省略 set、get、toString 方法
}

3 核心配置文件

配置文件中不是所有的配置都用到了,其他标签暂时作扩展。

jdbc-confg.properties

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis_study?serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=root

核心配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- 跟标签,mybatis在 Configuration 类中定义了一些别名 -->
<configuration>

    <!-- ======================== 读取外部配置文件 ========================= -->
    <!-- 用于读取外部的 properties 配置文件 -->
    <properties resource="jdbc-Config.properties"/>

    <!-- ======================== 重要配置项 ========================= -->
    <!-- 配置一些重要的配置项,如缓存、下划线命名规则转驼峰命名等 -->
    <settings>
        <!-- 下划线命名转驼峰命名 -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

    <!-- ======================== 起别名 ========================= -->
    <!-- 给 pojo 类取别名,在 映射文件中引用 pojo 类型的时候就可以直接使用别名,不区分大小写 -->
    <typeAliases>
        <!-- 配置单个 pojo -->
        <typeAlias type="com.pojo.Account" alias="Account"/>
        <!-- 批量起别名,可能会有同名 pojo,可以在实体类上使用 @Alias 取其他别名 -->
        <package name="com.pojo"/>
    </typeAliases>

    <!-- ======================== 数据源环境配置 ========================= -->
    <!-- 可以配置多个数据源,default 可以指定使用哪个数据源,值为具体环境配置的 id -->
    <!-- 通过 default 属性可以自由切换数据源 -->
    <environments default="mysql">
        <!-- 具体数据源配置,id 是该环境的唯一标识 -->
        <environment id="mysql">
            <!-- 事务管理类型 -->
            <transactionManager type="JDBC"/>
            <!-- jdbc连接信息,type 可取值:POOLED(采用池)、UNPOOLED(不采用池,每次访问新建连接)、JNDI(服务器容器,只能web项目用) -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

    <!-- ======================== 数据库厂商标识 ========================= -->
    <!-- type=DB_VENDOR ==>  VendorDatabaseIdProvider -->
    <databaseIdProvider type="DB_VENDOR">
        <property name="SQL Server" value="sqlserver"/>
        <property name="DB2" value="db2"/>
        <property name="Oracle" value="oracle" />
    </databaseIdProvider>

    <!-- ======================== 映射器 ========================= -->
    <!-- 注册 mapper,告诉 MyBatis 去哪里寻找 SQL 映射-->
    <mappers>
        <!-- 单个注册 -->
        <!-- resource 类路径下的文件 -->
        <!-- url,指定映射文件的 url,可以使用 file 协议指定本地 -->

        <mapper resource="com/mapper/demo2/AccountMapper.xml"/>

        <!-- 批量注册 -->
        <!-- name,指定包名,要使用批量注入必须保证 Mapper 接口和 Mapper映射文件的目录结构和命名完全一致 -->
        <!-- 例如:com.mapper.demo2.AccountMapper.java <==> com.mapper.demo2.Account.xml -->
        <!-- 这样作可以让 Java 编译后在同一个文件目录下 -->

        <!--<package name="com.mapper.demo2"/>-->
    </mappers>
</configuration>

4 Mapper 接口

public interface AccountMapper {
    //  查询所有
    List<Account> findAll();
    //  根据 ID 查询
    Account findById(Integer id);
    //  保存
    void saveAccount(Account account);
    //  更新
    void updateAccount(Account account);
    //  删除
    void deleteById(Integer id);
    //  模糊查询1 使用 ${} 拼接
    List<Account> findByName(String name);
    //  模糊查询2 使用 #{} 拼接
    List<Account> findByName2(String name);
    //  模糊查询3 使用 bind 标签拼接
    List<Account> findByName3(String name);
}

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

<!--
    mapper 标签是 映射文件的根标签,只有一个属性 namespace,用于指定对应 mapper 接口的全类名
-->
<mapper namespace="com.mapper.demo2.AccountMapper">

    <!-- 自定义结果集映射,将 pojo 类与 数据库中的字段名不同的地方作映射 -->
    <!-- 在核心配置文件中配置别名,所以可以直接使用 account ,不区分大小写-->
    <!-- 但是更建议使用全类名,可以 ctrl + 左键进入接口查看方法,这里作为演示,就用 account 了 -->
    <resultMap id="accountMap" type="account">
        <!-- id指主键、result指普通属性 -->
        <!-- column 指数据库字段名、property 指 pojo 属性名 -->
        <id column="id" property="id"/>
        <result column="name" property="accountName"/>
        <result column="money" property="nowMoney"/>
    </resultMap>

    <!-- ===============查询所有===================== -->
    <!-- 可以通过起别名,也可以通过自定义结果集映射来解决查询值为 null 的情况 -->
    <!-- 需要注意,起的别名也必须与 Java 类的属性名一致,不然查到的也是 null -->
    <select id="findAll" resultType="com.pojo.Account">
        select id,name as accountName,money as nowMoney from tb_account
    </select>

    <!-- ===============根据 id 查询===================== -->
    <!-- resultMap 指定自定义的结果集映射,值为自定义结果集的 id -->
    <!-- #{} 用于获取传入的参数 -->
    <!-- 如果传参只有一个 普通类型 或 String 参数,则命名可以随意 -->
    <!-- 如果是一个 pojo 对象,可以用 OGNL 表示式获取 pojo 的属性,详情见保存方法 -->
    <!-- #{} 是 PreparedStatement 中的占位符,可以将传入的单个参数放入占位符中 -->
    <select id="findById" resultMap="accountMap">
        select * from tb_account where id = #{accountId}
    </select>

    <!-- ===============保存方法===================== -->
    <!-- 没有返回值 -->
    <!-- 可以使用 selectKey 获取当前插入记录的 id 值 -->
    <insert id="saveAccount" parameterType="com.pojo.Account">
        <selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
            select last_insert_id();
        </selectKey>
        insert into tb_account(name,money) values (#{accountName},#{nowMoney})
    </insert>

    <!-- =============== 更新方法 ===================== -->
    <update id="updateAccount" parameterType="com.pojo.Account">
        update tb_account set money=#{nowMoney} where id = #{id}
    </update>

    <!-- =============== 删除方法 ===================== -->
    <delete id="deleteById">
        delete from tb_account where id = #{accountId}
    </delete>

    <!-- =============== 模糊查询1 ===================== -->
    <!-- ${} 是 Statement 的字符串拼接,有 sql 注入问题,但是能替代 #{} 不能使用的位置 -->
    <select id="findByName" resultMap="accountMap">
        select * from tb_account where name like '%${accountName}%'
    </select>

    <!-- =============== 模糊查询2 ===================== -->
    <select id="findByName2" resultMap="accountMap">
        select * from tb_account where name like #{accountName}
    </select>

    <!-- =============== 模糊查询3 ===================== -->
    <select id="findByName3" resultMap="accountMap">
        <bind name="accountName" value="'%' + accountName + '%'"/>
        select * from tb_account where name like #{accountName}
    </select>

</mapper>
  • 注意,编写好的 xml 映射文件一定要到核心配置文件中注册。

6 测试方法

public class Demo2Test {

    InputStream in = null;
    SqlSession sqlSession = null;
    AccountMapper mapper = null;

    @Before  //  测试方法执行之前执行
    public void init() throws Exception {
        // 1 将配置文件读到字节输入流
        in = Resources.getResourceAsStream("com/mapper/demo2/mybatis-config.xml");
        // 2 使用构建者读取字节流,创建工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        // 3 使用工厂创建 SqlSession 对象
        sqlSession = factory.openSession();
        // 4 使用 SqlSession 对象创建 Mapper 代理对象
        mapper = sqlSession.getMapper(AccountMapper.class);
    }

    @After  //  执行方法执行结束后执行
    public void after() throws Exception {
        // 6 释放资源
        in.close();
    }

    //  1 测试查询所有
    @Test
    public void testFindAll() {
        List<Account> accountList = mapper.findAll();
        for (Account account : accountList) {
            System.out.println(account);
        }
    }

    // 2 根据 id 查询
    @Test
    public void testFindById(){
        Account account = mapper.findById(1);
        System.out.println(account);
    }

    // 3 新增一条记录
    @Test
    public void testSave(){
        Account account = new Account();
        account.setAccountName("李华");
        System.out.println("提交前:" + account);
        mapper.saveAccount(account);
        //  提交事务!
        sqlSession.commit();
        //  获取到 key
        System.out.println("提交后:" + account);
    }

    // 4 修改一条数据,修改新增数据的 money
    @Test
    public void testUpdate(){
        Account account = new Account();
        account.setId(4);
        account.setNowMoney(10000.0);
        mapper.updateAccount(account);
        // 提交事务!
        sqlSession.commit();
    }

    // 5 删除一条数据
    @Test
    public void testDelete(){
        mapper.deleteById(4);
        // 提交事务
        sqlSession.commit();
    }

    // 6 模糊查询:可以再控制台看日志中发送的 sql 语句,区分 ${} 与 #{} 的区别
    @Test
    public void testFindByName(){
        //模糊查询1:使用 ${}
        List<Account> accountList1 = mapper.findByName("小");
        for (Account account : accountList1){
            System.out.println(account);
        }

        System.out.println(" ------- 分割线 -------- ");

        //模糊查询2:使用 #{},在外面拼接好再传入,更灵活
        List<Account> accountList2 = mapper.findByName2("%小%");
        for (Account account : accountList2){
            System.out.println(account);
        }

        System.out.println(" ------- 分割线 -------- ");

        //模糊查询3:使用 #{} + bind 标签,可以避免 sql 注入
        List<Account> accountList3 = mapper.findByName3("小");
        for (Account account : accountList3){
            System.out.println(account);
        }
    }
}
  • 需要注意的是,增、删、改操作需要提交事务,也可以将事务提交放到 after 方法中,这里写出来只是为了加深记忆。

7 #{} 与 ${} 取值的区别

  • #{}PreparedStatement 中的参数占位符,将传入的参数放到占位符的位置。
  • ${}Statement 中的字符串拼接,将传入的参数已字符串的形式拼接到 SQL 中,如果不是数字类型,需要加上单引号。
  • 开发中更常用 #{} 取值,相对更安全,使用 ${} 取值,更容易引起 sql 注入问题。

在这里插入图片描述

  • 这是测试模糊查询方法,第一个使用 ${} 取值,后两个使用 #{} 取值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值