简单使用MyBatis

Mybatis的全局文件设置

mybatis的全局配置文件mybatis-config.xml中,有很多设置和属性.如下

  • configuration(配置)
    • properties(属性)
    • settings(设置)
    • typeAliases(类型别名)
    • typeHandlers(类型处理器)
    • objectFactory(对象工厂)
    • plugins(插件)
    • environments(环境配置)
      • environment(环境变量)
        • transactionManager(事务管理器)
        • dataSource(数据源)
    • databaseIdProvider(数据库厂商标识)
    • mappers(映射器)

其中有很多设置和属性,但是我们只会涉及其中一部分

properties设置

一般会使用properties设置来加载 数据库配置文件 ,可以将数据库连接信息放在独立的配置文件中,方便后期维护

位置:在resources下

名字:任意,一般是 db.properties 或者 jdbc.properties

文件格式:properties格式,该文件格式是k=v形式

内容:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/java2212
jdbc.username=root
jdbc.password=123456

在mybatis的全局配置文件中加载该文件

<!-- 根标签 -->
<configuration>

    <!--    使用外部properties文件-->
    <properties resource="db.properties" />
    ....
    <!--
         jdbc连接属性,使用properties文件中的内容,
          使用${key}取出value
    -->
    <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>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qWAXsiMM-1663853746734)(day53_mybatis.assets/image-20220921101947672.png)]

typeAliases设置

在写映射文件时,resultType或者parameterType时,如果参数是类,就需要写全限定名,路径较长

解决方案:在mybatis全局配置文件中使用typeAliases设置类型别名即可

<!--类型别名-->
    <typeAliases>
        <typeAlias type="com.qf.model.User" alias="User"/>
    </typeAliases>

设置以后,就可以在resultType和parameterType中直接使用别名,User即可


但是随着业务的发展,项目中模块增多,实体类增多,类型别名的设置也会增多,太过于繁琐,就如以下代码

<typeAliases>
  <typeAlias alias="Author" type="com.qf.model.Author"/>
  <typeAlias alias="Blog" type="com.qf.model.Blog"/>
  <typeAlias alias="Comment" type="com.qf.model.Comment"/>
  <typeAlias alias="Post" type="com.qf.model.Post"/>
  <typeAlias alias="Section" type="com.qf.model.Section"/>
  <typeAlias alias="Tag" type="com.qf.model.Tag"/>
</typeAliases>

解决方法:

mybatis的类型别名给出另外一种方案,可以直接指定包,该包下面的所有类都可以直接使用类名当别名:

 <!--  类型别名  -->
    <typeAliases>
       <package name="com.qf.model"/>
    </typeAliases>

推荐使用这种方案

mappers设置

不同的加载位置

目前mapper.xml放在resources下面,但是有一部分的公司会将映射文件和接口放在一起,类似这样:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0Npre3Im-1663853746736)(day53_mybatis.assets/image-20220921104024740.png)]

当文件处于这种状态时,mappers中加载位置也要变化

原本我们直接写UserMapper.xml即可,但现在位置变了,就需要写全限定名,系统才能找到对应的xml文件

    <mappers>
        <!-- 加载映射文件 -->
        <mapper resource="com/qf/mapper/UserMapper.xml"/>
    </mappers>

如果以上操作后,发现运行失败,原因在于IDEA默认只会加载resources下面的xml文件,现在xml文件在java/com/qf/mapper包下,就无法将其编译加载至项目中

解决:只需要在pom.xml文件中添加一个build标签的代码

   <build>
        <!--IDEA的maven项目中,默认源代码目录下(java下)的xml等资源文件并不会
        在编译的时候一块打包进classes文件夹,而是直接舍弃掉。
            方法1:将xml或properties等配置文件放到resource下,并修
        改获取配置文件的代码,比如注册mapper.xml的位置等;
            方法2:如果执意java下,那么就需要在maven中添加过滤:
            将java下的xml过滤-->
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>*.xml</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>

再次运行即可

mapper的另一种加载方案

随着项目模块增多,使用mapper resource=“路径” 的方式加载会变得很繁琐,每多一个配置的xml文件就需要添加一行映射代码

mybatis提供了一种方便的加载方式,可以直接加载全部的映射文件

    <mappers>
        <!-- 这样就可以将com.qf.mapper下的所有映射文件全部加载 -->
       <package name="com.qf.mapper"/>
    </mappers>

但是这样做有前提:

1 接口和映射文件必须放在同一包下

2 接口和映射文件必须同名

否则就会绑定失败,导致无法执行SQL!

BUG

编码格式问题.

1 设置idea的编码格式为UTF-8

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dSyvGw8k-1663853746736)(D:/%E5%8D%83%E5%B3%B0%E4%B8%8A%E8%AF%BE/Every%20Day%20Stage3/day53/code/day53_mybatis.assets/image-20220921113343235.png)]

2 pom中加设置

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

再次运行

日志

mbatis框架内部使用了日志框架,默认使用的slf4j日志框架。

slf4j是日志门面,真正实现日志的是log4j框架,现在就在项目中使用log4j。

1 加入依赖

        <!--     日志依赖   -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

2 写配置文件

位置:resources下

名称:log4j.properties

# 日志有级别: 从小到大的级别(输出内容由详至简)
# debug < info < warn < error
log4j.rootLogger=debug, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

3 运行即可发现控制台有很多日志,可以通过调整级别控制输出的内容

# 日志有级别: 从小到大的级别(输出内容由详至简)
# debug < info < warn < error

4 按如上配置好,日志会比较多,但是一般只关注SQL的运行情况,所以我们可以配置日志只打印SQL部分

# 日志有级别: 从小到大的级别(输出内容由详至简)
# debug < info < warn < error
log4j.rootLogger=error

# 设置mapper接口类或者配置文件中mapper的路径为debug
log4j.logger.com.qf.mapper=debug,stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

动态SQL

动态SQL就是动态拼接SQL语句

语法:

实现代码复用

判断是否拼接

对数据进行遍历

sql和include

实现代码复用

如果映射文件中有部分代码重复率较高,可以使用标签将重复代码写进去,然后使用进行调用即可

   <!--  sql片段  -->
    <sql id="user_fields">
        u.id id,
        u.username,
        u.`password`,
        u.birthday,
        u.phone,
        u.address
    </sql>

    <select id="findUserById" resultType="User" parameterType="int">
        select
           <!--  引用sql片段  -->
           <include refid="user_fields"/>
        from user u where u.id = #{id}
    </select>

if和where

判断是否拼接sql语句,一般用于模糊查询

场景:模糊查询时,当没有传入关键词时,SQL语句就不拼接模糊查询的代码,若传值了,就拼接模糊查询的代码

//接口模糊查询方法
    List<User> findUserByKeyword(String keyword);
   <!--  模糊查询测试  -->
    <select id="findUserByKeyword" parameterType="String" resultType="User">
        select
            <include refid="user_fields"/>
        from
            user u
        <!--当下方if中判断成立,此处会自动拼接where关键词,以及if内的内容-->
        <!--当下方if中判断失败,则不拼接任何东西,包括where关键词-->
        <where>
            <if test="keyword != null and keyword != ''">
                username like concat('%',#{keyword},'%')
            </if>
        </where>
    </select>

foreach

在同一个列参考多个参数时

比如批量删除,一下传入多个id,接口方法参数就可以是数组,让sql语句同时删除多行

这时id列同时参考多个id,就可以使用foreach遍历集合

场景: 某些时候需要根据选择的不同的id来查询数据或删除数据

--同时删除多个的sql语句
select * from user where id in (29,30,31);
delete from user where id in (29,30,31);
//接口方法的参数是集合
    List<User> findUserByList(List<Integer> ids);
    <select id="findUserByList" parameterType="List" resultType="User">
        select * from user where id in
        <!--
            foreach 开始遍历
            collection 要遍历的集合,此处不是接口中参数名,必须是list
            item     遍历的得到到变量
            open  拼接左括号(
            close 拼接右括号 )
            separator 拼接变量间分隔符
        -->
        <foreach collection="list" item="id" open="(" close=")" separator=",">
            #{id}
        </foreach>
    </select>
//测试同时删除多个
    @Test
    public void findByList() throws IOException {

        // 配置文件路径
        String resource = "mybatis-config.xml";
        // 通过配置文件,获得输入流
        InputStream inputStream = Resources.getResourceAsStream(resource);

        // 通过流获得SqlSession工厂
        // SqlSession就是一次与SQL的交互
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        // 得到SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession( );

        // 动态代理的模式
        // 可以通过接口得到对应的映射文件,从而让映射文件执行
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        ArrayList<Integer> ids = new ArrayList<Integer>( );
        ids.add(29);
        ids.add(30);
        ids.add(31);
        List<User> list = mapper.findUserByList(ids);

        for (User user : list) {
            System.out.println(user );
        }
    }

多表联查

一对一查询

需求: 订单和用户是一对一,查询订单信息以及关联的用户信息.

数据库:

create table tb_order (
 id int primary key auto_increment,
 detail varchar(255),
 createTime datetime,
 uid int
)

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  `birthday` date DEFAULT NULL,
  `phone` varchar(255) DEFAULT NULL,
  `address` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=52 DEFAULT CHARSET=utf8;

实体类

public class Order {

    private int id;
    private String detail;
    private Date createTime;
    private int uid;
    
    // setter getter
}
// User类略

改造实体类,用于在查询出结果时封装数据

public class Order {

    private int id;
    private String detail;
    private Date createTime;
    private int uid;

    // 添加User类属性,用于封装查询出的User数据
    private User user;
    // getter和setter方法
}

写Mapper接口以及映射文件

public interface OrderMapper {
    // 查询订单
    List<Order> findAllOrderWithUser();
}
<mapper namespace="com.qf.mapper.OrderMapper">

    <!--
        一对一的封装,直接使用resultType无法封装成功
         需要使用resultMap单独对其中的user属性封装
         resultMap标签中的id,当前标签的唯一标识
         resultMap标签中的type,最终封装的实体类
     -->
    <resultMap id="orderWithUser" type="Order">
        <!-- id标签封装id属性
            column 结果集中的列名
            property是实体类属性
        -->
        <id column="id" property="id"/>
        <!--
			result标签封装其他属性
        -->
        <result column="detail" property="detail"/>
        <result column="createTime" property="createTime"/>
        <result column="uid" property="uid"/>
        <!-- 下面开始进行一对一的关联映射,使用association标签 -->
        <!-- 
            property:是最终实体类中的属性
            javaType: 指定属性的数据类型
        -->
        <association property="user" javaType="com.qf.model.User">
            <!-- column列是sql查询的列
                 property是关联映射的User的属性
            -->
            <id column="uid" property="id"/>
            <result column="username" property="username"/>
            <result column="password" property="password"/>
            <result column="birthday" property="birthday"/>
            <result column="phone" property="phone"/>
            <result column="address" property="address"/>
        </association>
    </resultMap>
    <!-- 
 		此处使用resultMap来引用的是上面resultMap标签的id
    -->
    <select id="findAllOrderWithUser" resultMap="orderWithUser">
        SELECT
        o.id,
        o.detail,
        o.createTime,
        u.id uid,
        u.username,
        u.`password`,
        u.birthday,
        u.phone,
        u.address
        FROM
        tb_order o,
        USER u
        WHERE
        o.uid = u.id
    </select>

</mapper>
    @Test
    public void one2one() throws IOException {

        // 配置文件路径
        String resource = "mybatis-config.xml";
        // 通过配置文件,获得输入流
        InputStream inputStream = Resources.getResourceAsStream(resource);

        // 通过流获得SqlSession工厂
        // SqlSession就是一次与SQL的交互
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        // 得到SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession( );

        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);

        List<Order> list = mapper.findAllOrderWithUser( );

        for (Order order : list) {
            System.out.println(order );
        }
    }

总结: mybatis实现一对一就是使用

​ restultMap内使用association来映射完成

一对多查询

需求: 用户和订单是一对多,查询一个用户信息以及关联的所有订单信息.

SQL:

SELECT
	o.id,
	o.detail,
	o.createTime,
	u.id uid,
	u.username,
	u.`password`,
	u.birthday,
	u.phone,
	u.address 
FROM
	USER u,
	tb_order o 
WHERE
	u.id = o.uid 
	AND u.id = 29

改造实体类

public class User {
    private int id;
    private String username;
    private String password;
    private Date birthday;
    private String phone;
    private String address;

    // 添加集合属性,用于存放查询的多个订单
    private List<Order> orderList;

接口和映射文件

public interface UserMapper {
    User findUserWithOrder(int id);
}
   <resultMap id="userWithOrder" type="User">
        <id column="uid" property="id"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
        <result column="birthday" property="birthday"/>
        <result column="phone" property="phone"/>
        <result column="address" property="address"/>
        <!--  开始一对多的封装: User类中的Order集合 -->
        <!--
            一对多使用<collection>标签
            property 是User类的数据
            ofType  是集合中存储的数据的类型
        -->
        <collection property="orderList" ofType="Order">
            <id column="id" property="id"/>
            <result column="detail" property="detail"/>
            <result column="createTime" property="createTime"/>
            <result column="uid" property="uid"/>
        </collection>
    </resultMap>

    <select id="findUserWithOrder" parameterType="int" resultMap="userWithOrder">
        SELECT
            o.id,
            o.detail,
            o.createTime,
            u.id uid,
            u.username,
            u.`password`,
            u.birthday,
            u.phone,
            u.address
        FROM
            USER u,
            tb_order o
        WHERE
            u.id = o.uid
        AND u.id = #{id}
    </select>

总结: mybatis实现一对多就是使用

<select id="findUserWithOrder" parameterType="int" resultMap="userWithOrder">
    SELECT
        o.id,
        o.detail,
        o.createTime,
        u.id uid,
        u.username,
        u.`password`,
        u.birthday,
        u.phone,
        u.address
    FROM
        USER u,
        tb_order o
    WHERE
        u.id = o.uid
    AND u.id = #{id}
</select>

> 总结: mybatis实现一对多就是使用
>
> ​	 restultMap内使用collection来映射完成
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值