-->

MyBatis 核心配置文件及映射文件详解

MyBatis是支持定制化SQL、存储过程以及高级映射的优秀的持久层框架,本文重点介绍MyBatis 核心配置文件及映射文件,需要的朋友可以参考下
 

什么是SSM?

 

IBatis提供的持久层框架包括SQLMap和Data Access Objects(DAO)

MyBatis特性

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

MyBatis和其它持久化技术对比

JDBC

1.SQL夹杂在java代码中耦合度高,导致硬编码内伤
2.维护不易且实际开发需求中SQL有变化,频繁修改的情况多见
3.代码冗长,开发效率低

Hibernate和JPA

1.操作简单,开发效率高
2.程序中的长难复杂SQL需要绕过框架
3.内部自动生产的SQL,不容易做特殊优化
4.基于全映射的全自动框架,大量字段的POJO进行部分映射比较困难
5.反射操作太多,导致数据库性能下降

MyBatis

1.轻量级,性能出色
2.SQL和java编码分开,功能边界清晰,java代码专注业务、SQL语句专注数据
3.开发效率稍逊于Hibernate,但是完全能够接受

创建MyBatis的核心配置文件

习惯上命名为mybatis-config.xml,这个文件名仅仅是建议,并非强制要求。将来整合Spring之后,这个配置文件可以省略,所以大家操作时可以直接复制、粘贴
核心配詈文件主要用于配置连接数据库的环境以及MyBatis的全同配置信息
核心配置文件存放的位置是srcimain/resources日录下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?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>
 
    <!--定义属性文件
        resource:从类路径下面读取外部文件
        url:从一个资源定位地址来读取配置文件
        提供参数使用: 可以使用 ${参数名} 进行参数引用
    -->
  <environments default="default">
        <!--环境变量-->
        <environment id="default">
            <!--事务管理器:由JDBC管理事务 -->
            <transactionManager type="JDBC"/>
            <!--数据源配置信息:POOLED 使用连接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="2022"/>
            </dataSource>
        </environment>
    </environments>
 
    <!-- 加载其他的映射文件 -->
    <mappers>
        <mapper resource="org/mybatis/example/BlogMapper.xml"/>
    </mappers>
</configuration>

创建mapper接口

MyBatls中的mapper接口相当于以前的dao。但是区别在于,mapper仅仅是接口,我们不需要提供实现类。

创建MyBatis的映射文件

MyBatls中的mapper接口相当于以前的dao。但是区别在于,mapper仅仅是接口,我们不需要提供实现类。

创建MyBatis的映射文件
相关概念:ORM(Object Relationship Mapping)对象关系映射
.对象:java的实体类对象
.关系:关系型数据库
.映射:二者之间的对应关系
映射文件的命名规则->表所对应的实体类的类名+Mapper.xml

测试添加功能

SqlSession:代表java程序和数据库之间的会话。(HttpSession是java程序和浏览器之间的会话)
SqlSessionFactory:是”生产SqlSession的”工厂。
工厂模式:如果创建某一个对象,使用的过程基本固定,那么我们就可以把创建这个对象的相关代码封装到一个”工厂类”中,以后都使用这个工厂类来”生产”我们需要的对象

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@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 result = mapper.insertUser();
    //提交事务
    sqlSession.commit();
    System.out.println("result:"+result);
}

需要手动提交数据的原因

在这里插入图片描述

优化功能

对于简单的SQL我们没必要每次都手动提交数据,因此可以把默认的手动提交,变为自动提交

 

加入log4j日志文件功能

第一步 加入依赖

1
2
3
4
5
6
<!--log4j日志-->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

第二步 加入配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?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>

日志的级别

FATA(致命)>ERROR(错误)>WARN(警告)>INFO(信息)>DEBUG(调试)
从左到右打印的内容越来越详细

 

MyBatis核心配置文件之environment

 

 

 

 

MyBatis核心配置文件之properties

将数据库信息写在properties里面,之后在配置文件里面引用
第一步:创建properties文件,并且编写数据库配置信息

 

第二步:在配置文件中引入properties文件

 

第三步:编写数据库连接池

 

MyBatis核心配置文件之typeAliases

MyBatis核心配置文件中,标签的顺序:
propertiers?,setting?,typeAliases?,typeHandlers?
objectFactory?,objectWrapperFactory?,reflectorFactory?,
plugins?,environments?,dataseIdProvider?,mappers?
为了避免重复频繁的写在mapper中的resultType写全类名

 

所以可以在配置文件中利用typeAliases标签创建一个简短的别名

 

随后在mapper文件写sql语句时可以

 

注意
不区分大小写
若不设置属性alis

alias="User"

则会有默认别名就是类名不区分大小写

 

MyBatis核心配置文件之mappers

 

 

当表的数量太多的时候,需要大量的mapper标签来引入映射文件,为此我们可以通过引入包的方式来引入映射文件
以包为单位引入映射文件
要求:
1.mapper接口所在的包要和映射文件所在的包一致
2.mapper接口要和映射文件的名字一致

 

思考:映射文件中的SQL该如何拼接?

到此这篇关于MyBatis 核心配置文件就介绍到这了.下面进入映射文件介绍

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

XML核心映射文件介绍

MyBatis 的真正强大在于它的语句映射,它指导着 Mybatis 如何进行数据库的增删改查。在之前的demo当中已简单使用过,写sql的那个XML 文件就是映射文件。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.pingguo.bloomtest.dao.UserMapper">
    <select id="getUserById" resultType="com.pingguo.bloomtest.pojo.User" databaseId="mysql">
      select * from user where id = #{id}
    </select>
</mapper>

SQL 映射文件只有很少的几个顶级元素(按照应被定义的顺序列出):

  • cache – 该命名空间的缓存配置。
  • cache-ref – 引用其它命名空间的缓存配置。
  • resultMap – 描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。
  • parameterMap – 老式风格的参数映射。此元素已被废弃,并可能在将来被移除!请使用行内参数映射。文档中不会介绍此元素。
  • sql – 可被其它语句引用的可重用语句块。
  • insert – 映射插入语句。
  • update – 映射更新语句。
  • delete – 映射删除语句。
  • select – 映射查询语句。

不过,先来看下增删改查。

一、增删改查速览

我继续在接口里新增几个方法(查询已有):

public interface UserMapper {
    // 查询
    User getUserById(Integer id);
    // 新增
    void addUser(User user);
    // 修改
    void updateUser(User user);
    // 删除
    void deleteUser(Long id);
}

在映射文件UserMapper.xml中,使用insertupdatedelete标签来写对应方法的sql:

<!--新增-->
<insert id="addUser">
    insert into user(username, password, createTime, updateTime)
    values(#{username}, #{password}, #{createTime}, #{updateTime})
</insert>

<!--更新-->
<update id="updateUser">
    update user
      set username=#{username}, password=#{password}, createTime=#{createTime}, updateTime=#{updateTime}
      where id=#{id}
</update>

<!--删除-->
<delete id="deleteUser">
    delete from user where id=#{id}
</delete>

另外,mybatis 允许增删改直接定义如下的返回值:Integer、Long、Boolean。那么接口里定义的方法就可以写成这样:

public interface UserMapper {
    // 查询
    User getUserById(Integer id);
    // 新增
    boolean addUser(User user);
    // 修改
    boolean updateUser(User user);
    // 删除
    boolean deleteUser(Long id);
}

addUser方法来说,新增成功之后返回的就是true

在测试类里可以测试下上面几个方法,这里贴出来测试一下新增:

@Test
void test3() throws IOException{
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    // 获取到的 SqlSession 不会自动提交数据
    SqlSession session = sqlSessionFactory.openSession();
    User newUser = new User();
    newUser.setUsername("新用户1");
    newUser.setPassword("111111");
    newUser.setCreateTime(new Date());
    newUser.setUpdateTime(new Date());
    try {
        UserMapper userMapper = session.getMapper(UserMapper.class);
        userMapper.addUser(newUser);
        // 需要这里手动提交
        session.commit();
    } finally {
        session.close();
    }
}

注意这里sqlSessionFactory.openSession()不会自动提交数据,需要session.commit()手动提交。如果需要自动提交,里面传入true即可:

sqlSessionFactory.openSession(true)

新增成功。

其他几个也成功通过测试。

二、insert获取自增主键的值

mysql 的自增主键,mybatis 也可以获取到,只需要添加一个属性useGeneratedKeys,默认是false

那获取到的主键值,可以通过keyProperty将这个值封装给 Javabean 的某个属性,比如User类中的id

<!--新增-->
<insert id="addUser" useGeneratedKeys="true" keyProperty="id">
    insert into user(username, password, createTime, updateTime)
    values(#{username}, #{password}, #{createTime}, #{updateTime})
</insert>

可以在之前的测试方法里加一个打印,看下获取到的主键值:

成功获取到主键值为 12 。

查看数据库表里新增多数据主键就是 12 。

三、单个参数、多个参数、对象

1. 单个参数

拿上面根据 id 进行查询为例:

<select id="getUserById" resultType="com.pingguo.bloomtest.pojo.User" databaseId="mysql">
  select * from user where id = #{id}
</select>

使用#{参数名},mybatis就会正确取出参数值。

当只有一个参数的时候,mybatis 不会做特殊处理,比如sql中的where条件是根据id来查询,但我就算写#{abc},也正常查询。

2. 多个参数

在接口UserMapper里再定义一个新的方法,里面传入多个参数:

// 查询 使用多个参数
User getUserByIdAndUsername(Integer id, String username);

对应的增加sql映射:

<select id="getUserByIdAndUsername" resultType="com.pingguo.bloomtest.pojo.User" databaseId="mysql">
  select * from user where id = #{id} and username=#{username}
</select>

测试一下,可以正常查询。

@Test
void test2params() throws IOException {
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    SqlSession session = sqlSessionFactory.openSession();
    UserMapper userMapper = session.getMapper(UserMapper.class);
    System.out.println(userMapper.getUserByIdAndUsername(3, "大周"));
}

3. 对象

如果多个参数正好是我们业务逻辑的数据模型,那可以直接传入对象,比如POJO,通过#{属性名}取出属性值。

如果多个参数没有对应的POJO,为了方便,也可以传入 Map 。

在 UserMapper 里增加方法:

    User getUserByMap(Map<String, Object> map);

sql 映射文件增加对应配置:

    <select id="getUserByMap" resultType="com.pingguo.bloomtest.pojo.User" databaseId="mysql">
      select * from user where id = #{id} and username=#{username}
    </select>

新增个测试方法,查询正常。

    @Test
    void testByMap() throws IOException {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        SqlSession session = sqlSessionFactory.openSession();
        UserMapper userMapper = session.getMapper(UserMapper.class);

        Map<String, Object> map = new HashMap<>();
        map.put("id", 3);
        map.put("username", "大周");
        System.out.println(userMapper.getUserByMap(map));
    }

如果上述这种 map 还要经常使用,推荐编写一个TO(Transfer Object)数据传输对象。

四、$ 和 # 取值

mybatis 中是采用#{}${}都是可以取值的,但是两者还是有区别的,比如:

    <select id="getUserByIdAndUsername" resultType="com.pingguo.bloomtest.pojo.User" databaseId="mysql">
      select * from user where id = ${id} and username=#{username}
    </select>

我在这里把2个参数分别用了不同的方法来取值:${id}#{username},然后执行之前的测试函数,看下打印结果。

区别就是:

  • #{},是以预编译形式,讲参数设置到 sql 语句中
  • ${},取出的值直接拼装在 sql 语句中,会存在一定的安全问题

大多数情况下,我们都去使用#{}

不过在某些情况下,还是会用到${}。比如一个工资表按照年份进行了拆分,表名前面是年份,那么要动态查询表的时候,年份就是个变量。

表名是不能预编译的,所以不能使用#{}。对于这种原生JDBC不支持占位符的地方,就可以使用${}

select * from ${year}_salary where xxx;

再比如,用到排序,我想把排序的条件和升序降序可以动态的穿进来,也可以使用${}

select * user order by ${age} ${desc_order};

五、select 元素

1. select 返回 list

如果我定义了一个查询,返回的是一个 list。

    List<User> getUserByUsernameLike(String username);

sql 映射文件这样写:

    <select id="getUserByLastNameLike" resultType="com.pingguo.bloomtest.pojo.User" databaseId="mysql">
      select * from user where username like #{username}
    </select>

注意这里如果返回的是一个集合类型,resultType里要写集合中的类型。

2. select 返回 map

如果需要返回一条记录的 map,key 就是列名,value 就是对应的值。

Map<String, Object> getUserByIdReturnMap(Integer id);

sql 映射文件这样写:

    <select id="getUserByIdReturnMap" resultType="map">
        select * from user where id = #{id}
    </select>

测试下,查询正常。

如果需要封装多条记录比如Map<Integer, User>,key 是记录的主键,value 是记录封装后的 javabean 。

Map<Integer, User> getUserByUsernameReturnMap(String username);

sql 映射文件:

    <select id="getUserByUsernameReturnMap" resultType="com.pingguo.bloomtest.pojo.User">
        select * from user where username like #{username}
    </select>

这里的返回类型还是 User,现在 value 有了,那么如何把主键作为 map 的 key 呢?

使用注解@MapKey("id"),告诉 mybatis 使用哪个属性作为 key:

    @MapKey("id")
    Map<Integer, User> getUserByUsernameReturnMap(String username);

测试一下:

如果换成其他属性作为 key 也是可以的。

 

posted @ 2023-08-22 10:52  角刀牛Java  阅读(324)  评论(0编辑  收藏  举报