关于Mybatis的使用

发布于:2023-01-05 ⋅ 阅读:(535) ⋅ 点赞:(0)

Mybatis的使用

1.Mybatis特性

  • MyBatis是支持定制化SQL、存储过程以及高级映射的优秀的持久层框架
  • MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集
  • MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的java对象)映射成数据库中的记录
  • MyBatis是一个半自动化的ORM(Object Relation Mapping)框架

2.和其他持久层技术对比

  • JDBC
    • SQL夹杂在Java代码中耦合度高,导致硬编码内伤
    • 维护不易且实际开发需求中SQL有变化,频繁修改的情况多见
    • 代码冗长,开发效率低
  • Hibernate和JPA
    • 操作简单,开发效率高
    • 程序中的长难复杂SQL需要绕过框架
    • 内部自动生产的SQL,不容易做特殊优化
    • 基于全映射的全自动框架,大量字段的POJO进行部分映射时比较困难
    • 反射操作太多,导致数据库性能下降
  • Mybatis
    • 轻量级,性能出色
    • SQL和Java编码分开,功能边界清晰。Java代码专注业务、SQL语句专注数据
    • 开发效率稍逊于Hibernate,但是完全能够接受

3.MyBatis环境搭建

1.创建一个Maven项目:

创建

2.自己安装mysql

相关参考教程

  • 创建数据库testdb;
CREATE DATABASE testdb CHARACTER SET utf8;
  • 创建user表
DROP TABLE IF EXISTS user;
create table user
(
    id int auto_increment not null primary key,
    name varchar(30) not null,
    age int not null
);

3.构造目录

在这里插入图片描述

4.构建文件

  • 第一步在resources目录下创建核心配置文件mybatis-config.xml文件

    • 文件内容:
<?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">
<configuration>
    <!--导入properties文件-->
    <properties resource="application.yaml"/>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <!--引入映射文件-->
    <mappers>
        <mapper resource="mappers/UserMapper.xml"/>
    </mappers>
</configuration>
  • 第二步在resources下创建文件application.yaml文件。
    • 文件内容:
#驱动mysql5.5以上为com.mysql.cj.jdbc.Driver,mysql5.5以下为com.mysql.jdbc.Driver
driver: com.mysql.cj.jdbc.Driver
#url换成自己的url:jdbc:mysql://ip:port/testdb?characterEncoding=utf8
url: jdbc:mysql://172.17.0.2:3306/testdb?characterEncoding=utf8
#用户名,生产环境不建议使用root账户,此处仅做实验
username: root
#密码改为自己的
password: 123456
  • 第三步:打开pom.xml引入mysql-connector-java、myBatis以及lombok依赖:
    • 依赖内容:
 <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.24</version>
    </dependency>
<!--引入myBatis依赖-->
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.10</version>
    </dependency>
    <!--引入mysql-connector-java-->
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.30</version>
    </dependency>
  • 第四步:在pojo目录下创建User类:
    • User类的结构为:
package org.example.pojo;
import lombok.*;
/**
 * @author mr
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private int age;
}
  • 第五步:在org.example.mapper目录下为User类创建UserMapper接口
    • 接口UserMapper:
package org.example.mapper;
/**
 * @author mr
 */
public interface UserMapper {
    /**
     * MyBatis面向接口编程的两个一致:
     * 1、映射文件的namespace要和mapper接口的全类名保持一致
     * 2、映射文件中SQL语句的id要和mapper接口中的方法名保持一致
     *
     * 表--实体类--mapper--映射文件
     * */
    int insertUser();
}
  • 第六步:在resource/mappers下为该UserMapper接口创建映射文件
    • UserMapper.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org/DTD Mapper 3.0"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mapper.UserMapper">
    <!--int insertUser();-->
    <insert id="insertUser">
        insert into user values(null ,"cxj",23);
    </insert>
</mapper>

对应关系图:

  • 对应关系图
  • 第七步:在test/org/example/AppTest.java里添加测试方法:testMyBatis
    测试方法
package org.example;
import static org.junit.Assert.assertTrue;
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.example.mapper.UserMapper;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
/**
 * Unit test for simple App.
 */
public class AppTest 
{
    /**
     * Rigorous Test :-)
     */
    @Test
    public void shouldAnswerWithTrue()
    {
        assertTrue( true );
    }
    @Test
    public void testMyBatis() throws IOException {
        //加载核心配置文件
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        //获取SqlSessionFactoryBuilder
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        //获取SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
        //获取SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //获取mapper接口对象,底层是代理模式
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int i = mapper.insertUser();
        System.out.println("result:"+i);
    }
}

第八步:运行测试方法–>testMyBatis(),得到运行结果:
result

  • 第九步:查看数据库数据进行验证,发现数据为空。
    事务提交
  • 主要原因是我们的事务提交在配置中配置的事务管理类型是JDBC–>需要手动提交。事务管理
    第十步:事务提交,再次执行,然后查询,发现数据库user表有新增记录。
    事务提交
    perfect
    此处是9,不是一,因为我们执行SQL而不提交事务的情况下它的id是会被占用的。
  • 第十一步:开启事务自动提交功能
    • myBatis默认手动提交事务
      autoCommit
  • 第十二步:配置myBatis日志
    • pom.xml加入log4J依赖
    • 在resources下创建文件log4j.xml
<dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.16</version>
</dependency>
日志的级别:
FATAL(致命)>ERROR(错误)>WRAN(警告)>INFO(信息)>DEBUG(调试)
从左到右打印的内容越来越细

log4j.xml内容:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
    <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
        <param name="Encoding" value="UTF-8" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n" />
        </layout>
    </appender>
    <logger name="java.sql">
        <level value="debug" />
    </logger>
    <logger name="org.apache.ibatis">
        <level value="info" />
    </logger>
    <root>
        <level value="debug" />
        <appender-ref ref="STDOUT" />
    </root>
</log4j:configuration>

运行日志输出:
log4j

  • 第十三步
    • 关于映射文件如何获取传入的参数问题。
      首先对接口函数进行改造:
      insert
      其次:映射文件的插入SQL对应修改:
      声明parameterType="org.example.pojo.User"即参数类型为pojo的User类型,然后采用#{属性名}的方式获取对象的属性值对应填充。
      mapper.xml
      测试:
      test
      结果:
      test
  • 第十四步:其它的传参方法。
    • 多参数传值:
      UserMapper接口里添加User selectUser(int id,String name,int age);抽象方法。selectUser
      UserMapper.xml里添加对应的mapper映射:
<select id="selectUser" resultType="org.example.pojo.User">
        select * from user where id=#{param1} and name=#{param2} and age=#{param3}
</select>

selectUser
测试:目前mysql数据库中存在的记录。
record
测试代码:
TestCode
测试结果:result
注:对于多值的传入,大家需要明白的一点就是,mybatis都会将传入的数据封装成map对象,通过key来得到值。也就是说此处mybatis将三个参数值封装成Map.Entry(param1,id),Map.Entry(param2,name)和Map.Entry(param3,age),多值输入底层其实是Map传参。

  • Map传值,在映射文件中通过#{key}来获取对应的值。
    UserMapper里新增int updateUser(HashMap<String,Object> map);抽象方法。
    UserMapper
    为抽象方法int updateUser(HashMap<String,Object> map);编写对应的mapper->SQL。UserMapper.xml

演示完多参数传递了,将User selectUser(int id,String name,int age);改为User selectUser(int id);我相信难不倒大家~
测试代码:
testCode
测试结果:
result

  • 传值方式有多参传值Map传值对象传值注解传值
    • 注解传值:在UserMapper接口里添加int deleteUser(@Param("id") int id,@Param("name") String name,@Param("age") int age);抽象方法。
      UserMapper
      在UserMapper.xml中添加对应的mapper->SQL:
      UserMapper.xml
      测试代码:
      testCode
      测试结果:
      testResult
      四种方式对比图:
      compare
      通过对比可以得知,四种传参方式,除了对象传参需要在UserMapper.xml特别声明参数类型parameterType="org.example.pojo.User"外,其余均一致。四种传参方式的共同点是均采用#{属性TAG}获取参数值。
  • 补充说明:查询所有数据。
    • 查询符合条件的所有数据。
      getAll
      测试代码:
      testCode
      测试结果:
      testResult
      注:查询功能必须设置resultType或resultMap,resultType:设置默认的映射关系,resultMap设置自定义的映射关系。

4.配置文件详解

  • mybatis-config.xml
<?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">
<configuration>
    <!--导入properties文件-->
    <properties resource="application.yaml"/>
    <environments default="development">
        <!--environment:配置某个具体的环境
               属性:
                  id:表示连接数据库的环境的唯一标识,不能重复。
                 -->
        <environment id="development">
           <!--transactionManager:设置事务的管理方式
                      属性:
                          type="JDBC|MANAGED"
                          JDBC:表示当前环境中执行SQL时,使用的是JDBC中原生的事务管理方式
                          MANAGED:表示被管理,例如Spring
                      -->
            <transactionManager type="JDBC"/>
            <!--dataSource:配置数据源
            属性:
                 type:设置数据源的类型
                 type="POOLED|UNPOOLED|JNDI"
            POOLED:表示数据库连接池缓存数据库连接
            UNPOOLED:表示不使用数据库连接池
            JNDI:表示使用上下文中的数据源
            -->
            <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>
    <!--引入映射文件-->
    <mappers>
        <mapper resource="mappers/UserMapper.xml"/>
    </mappers>
</configuration>
  • 关于类型别名:
    • myatis-config.xml 中起了类型别名之后,就可以在UserMappermapper文件中使用别名代替全类名。typeAliases
    • 最常用的设置别名的方式,以包为单位批量设置默认别名即类名的大小写形式作为别名,关键字package
      package
      关于mappers标签,
      注意:在resources下创建包的时候,如果我们采用cn.edu.xaut.mybatis.xml创建,创建出来的结果是一个目录,而不是分层的多级目录,在resources下创建包的时候,我们采用cn/edu/xaut/mybatis/xml创建的包才是多层的分级目录。
      error
      图示:
      errorResult
      以包为单位引入mapper.xml映射文件,需要注意的两点。
      attentions
  • 首先为什么需要目录结构一致呢,如下图可知MyBatis在编译时可以将javaresources相同目录结构的文件放到一起,而mapper接口名称为什么要和它的映射文件名称保持一致呢,其实主要是为了能在调用根据mapper接口生成的动态代理对象的某个SQL方法时,能根据mapper接口名.xml找到对应的映射文件并根据id定位到方法。

why

5.MyBatis中获取参数值的两种方式(重点)

  • MyBatis获取参数值的两种方式:${}#{}
  • ${}的本质就是字符串拼接,#{}的本质就是占位符赋值。
  • ${}使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号;但是#{}使用占位符赋值的方式拼接sql,此时为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号。
  • ${}容易引起SQL注入,所以平时最常用的是占位符赋值#{}
    diagram
  • MyBatis获取参数值的各种情况:
    • 1.mapper接口方法的参数为单个的字面量类型
      • 可以通过${}#{}以任意的名称获得参数值,但是需要注意${}的单引号问题。
      • 虽然可以通过任意的名称获得参数值,但是建议用参数值的名称来获取,做到见名知意,此处可以通过任意的名称获取参数值。

four    methods

  • 2.对于多个参数的传送,MyBatis将会把所有的参数封装到Map对象中,键值呢,分别为arg0:参数1,arg1:参数2,param1:参数1,param2:参数2,我们在执行对应的SQL的时候只需要通过#{arg0}/#{param1}获取参数1并进行对应填充复制,以及通过#{arg1}/#{param2}获取参数2等依次类推并进行填赋值或者字符串拼接${arg0}/${param1}获取参数值并进行拼接(当然由于字符串拼接会导致SQL注入,因此并不建议采用)。
    many
    more
  • 3.自封装Map<String,Object>就很好理解了,话不多说,如下图。
    • 注意点:1.'${}' #{}可以混用即可以在同一个SQL语句中出现(本人亲测)。
    • 注意点:2.用${}时需要注意,对于字符值我们需要加''用于字符串的拼接,而对于int类型的数据,我们加单引号'${}'或者不加单引号${},MyBatis均能进行正确解析(本人亲测)。
      manyType
  • 4.参数为实体类对象(常用)
    • 只需要通过#{}${}以属性的方式访问属性值即可,但是需要注意'${}'''问题。
      entry
      另外,附上'${}'#{}可以混用的证据。在这里插入图片描述
  • 5.命名参数(常用)
    • 使用@Param注解命名参数,此时MyBatis会将这些参数放在一个Map集合中,以两种方式进行存储。
      • @Param注解的值为键,以参数为值。
      • param1param2为键,以参数为值。
      • 因此只需要通过#{}'${}'以键的方式访问值即可,但是需要注意${}的单引号''问题,且${}方式容易引起SQL注入
        normal
  • 底层Map放了两套key:value的地方(一个是param1:value,另一个是id:value,此处id是@Param("id")的id)。
    theory

6.MyBatis的各种查询功能

  • 1、若查询出的数据只有一条
    • 可以通过实体类接收对象
    • 可以通过集合来接收对象
    • 可以通过Map来接收对象
      all

通过Map接收的结果: 在这里插入图片描述

  • 2、若查询出的数据有多条,一定不能通过实体对象来接收,此时会抛出TooManyResultsException。
    • 可以通过list集合接收
    • 可以通过Map类型的集合来接收
      • 通过集合来接收的两种方式:
        two
    • 直接通过Map集合来接收,需要在mapper接口的方法上添加@MapKey("key") @Mapkey("id")
    • Map集合的结果如下:result - 3、查询某个表中的总记录数。
    • 注意:当我们在选择count(*)count(1)count(字段)时注意区别。
      • count(*)count(1):

        • 使用count函数,当要统计的数量比较大时,发现count(*)花费的时间比较多,相对来说count(1)花费的时间比较少。
        • 如果你的数据表没有主键,那么count(1)比count(*)快;如果有主键的话,那主键(联合主键)作为count的条件也比count(*)要快 。
        • 如果你的表只有一个字段的话那count(*)就是最快的。
        • 如果count(1)是聚索引,id,那肯定是count(1)快,但是差的很小的。因为count(*),自动会优化指定到那一个字段。所以没必要去count(1),用count(*),sql会帮你完成优化。此时count(1)和count(*)基本没有区别!
      • count(*)count(列名):

        • 数据记录都不为空的时候查询出来结果上没有差别的;
        • count(*)(是针对全表)将返回表格中所有存在的行的总数包括值为null的行
        • count(列名)(是针对某一列)将返回表格中某一列除去null以外的所有行的总数。
      • 引申:

        • distinct 列名,得到的结果将是除去值为null和重复数据后的结果。
          count
  • 4、MyBatis默认的类型别名
Alias Mapping Type
_byte byte
_long long
_short short
_int int
_integer int
_double double
_float float
_boolean boolean
string String
byte Byte
long Long
short Short
int Integer
integer Integer
double Double
float Float
boolean Boolean
date Date
decimal BigDecimal
object Object
map Map
hashmap HashMap
list List
arraylist ArrayList
collection Collection
iterator Iterator
  • 5.MyBatis特殊SQL的执行

    • 1.模糊查询
      模糊查询的SQL#{}${}用法。模糊查询
  • 2.批量删除

    • 批量删除,采用SQL语句的in关键字。
      deleteMany
    • 实验结果图:
      result
  • 3.动态设置表名


网站公告

今日签到

点亮在社区的每一天
去签到