Mybatis笔记

创建第一个mybatis程序


  1. 准备数据库环境

  2. 搭建普通maven项目环境

  3. 倒入maven依赖

  4. 删除src目录(为了新建后面的子模块)

  5. 在子模块中编写mybatis的核心配置文件,这个框架需要配置之后才能使用

    <?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>
        <!--    mybatis核心配置文件-->
        <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://localhost:3306/mybatis?useUnicode=true&amp;characterEncoding=UTF-8&amp;useSSL=false"/>
                    <property name="username" value="root"/>
                    <property name="password" value="123456"/>
                </dataSource>
            </environment>
        </environments>
    
    </configuration>
    
  6. 编写mybatis工具类,因为需要从配置文件中拿到建造者来建造工厂,读取配置文件这个过程可以写成工具类

    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;
    
    public class MybatisUtils {
    
        private static SqlSessionFactory sqlSessionFactory;
    
        static {
            String resource = "mybatis-config.xml";
            InputStream inputStream = null;
            try {
                inputStream = Resources.getResourceAsStream(resource);
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public static SqlSession getSqlSession() {
            return sqlSessionFactory.openSession();
    
        }
    }
    
  7. 开始写程序(就按照mvc三层架构开始)

    • dao层接口

      package com.zhong.dao;
      
      import com.zhong.pojo.User;
      
      import java.util.List;
      
      public interface UserDao {
          public List<User> getUserList();
      }
      
    • dao层实现类(这里是配置文件来实现,由原来的impl转换成mapper.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.zhong.dao.UserDao">
          <select id="getUserList" resultType="com.zhong.pojo.User">
          select * from `user`;
        </select>
      </mapper>
      
    • 测试问题。因为我们的mapper.xml不是建在resources文件夹下的,所以需要对mapper.xml进行注册。但是由于maven无法导出Java文件夹下的配置文件。所以需要在xml中配置过滤,让maven能够导出我们的mapper.xml。或者把mapper.xml直接建立在resources文件夹下,然后在配置中文件路径写文件名即可

Map


使用map键值对来传递参数

配置解析


核心配置

环境配置

学会配置多套环境

属性

可以通过properties来动态的配置mybatis的核心配置文件。通过在核心配置文件中的properties的属性来引用

别名

在配置文件中,使用完全限定名规定类型,我们可以使用别名来为减少完全限定名的使用

<!--    给实体类起别名-->
    <typeAliases>
        <typeAlias type="com.zhong.pojo.User" alias="User"></typeAlias>
    </typeAliases>

包扫描,会默认的给包中的实体类起一个首字母小写的类名的别名

<!--    给实体类起别名-->
    <typeAliases>
        <package name="com.zhong.pojo"/>
    </typeAliases>

起别名也可以直接在实体类里面实现,在实体类中使用注解@Alias(“别名”)。在所有的起别名的方式中,注解的优先级最高

设置

映射器

注册mapper,就像使用配置文件去实现接口必须要注册一样。它有三种方式resouce使用/来分隔。class使用.分隔。以及打包一个包内的mapper package name=…

第二第三种方式需要注意的是,配置文件必须和接口同名,而且配置文件必须和接口在同一个包下

生命周期和作用域

错误的使用生命周期和作用域会导致严重的并发问题

ResultMap


用来解决数据库字段名和封装的对象的属性名不一致的问题,当这两个不一致的时候,mybatis无法将数据库查出来的数据放到对应的位置上

<resultMap id="UserMap" type="User">
    <result column="id" property="id"></result>
    <result column="name" property="name"></result>
    <result column="pwd" property="password"></result>
</resultMap>

    <select id="getUserById" parameterType="int" resultMap="UserMap">
        select * from `user` where id = #{id};
    </select>

日志

日志工厂

STDOUT_LOGGING 标准日志输出,开箱即用

<settings>
    <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

LOG4J 需要配置(IDEA 2022.1弃用log4j)

导包

<!-- 日志导包       -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.12</version>
</dependency>

log4j配置文件

#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file

#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n

#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/kuang.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n

#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

使用

static Logger logger = Logger.getLogger(UserDaoTest.class);


@Test
public void testLog4j() {
    logger.info("info");
    logger.debug("debug");
    logger.error("error");
}

分页


List<User> getUserByLimit(Map<String,Object> map);
<select id="getUserByLimit" resultType="User" parameterType="map" resultMap="UserMap">
    select * from mybatis.user limit #{startIndex},#{pageSize};
</select>
@Test
public void testLimit(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);

    HashMap<String, Object> map = new HashMap<String, Object>();
    map.put("startIndex",0);
    map.put("pageSize",2);

    List<User> userByLimit = mapper.getUserByLimit(map);
    for (User user : userByLimit) {
        System.out.println(user);
    }

    sqlSession.close();
}

使用注解开发


当我们需要使用一些简单的sql语句,可以使用注解来代替配置xml文件。这会让配置文件看起来比较干净整洁。但是使用一些复杂的sql语句的时候,在使用xml配置文件还是很有必要的。比如数据库字段和实体类数据名字不一样这样就映射不了

直接在接口的方法上面写@select("这里写你的查询sql")即可

@Select("select * from `user`")
List<User> getUsers();
<mappers>
    <!--<mapper resource="com/zhong/dao/UserMapper.xml"></mapper>-->
    <mapper class="com.zhong.dao.UserMapper"></mapper>
</mappers>

参数注解

在使用注解写sql语句的时候,如果方法本身需要一个外部的参数,那么在sql语句中为了使用到这个参数,需要在参数列表的参数前面加上参数注解@param("被sql调用的参数名")。参数注解只使用在基本类型和String,引用类型不需要参数注解

Lombok使用(重要):


这是一个java的库,它是一个插件、构建工具。使用注释就可以写getter等方法。可以用idea的插件市场安装

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.10</version>
</dependency>

常用的注解

@Data//getter...等方法
@AllArgsConstructor//所有参数的构造方法
@NoArgsConstructor//无参数构造方法
@ToString

多对一的处理


我们需要在实现xml文件中关联sql语句,并且做结果集映射

按照查询嵌套处理

<resultMap id="StudentTeacher" type="Student">
    <!--简单映射可以直接使用result,但是对于复杂的对象需要进行特殊的处理-->
    <!--对象:association(多对一)
    集合:collection(一对多)-->
    <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"></association>
</resultMap>

<select id="getStudent" resultMap="StudentTeacher">
    select * from mybatis.student;
</select>

<select id="getTeacher" resultType="Teacher">
    select * from mybatis.teacher where id = #{id};
</select>

按结果嵌套查询

<select id="getStudent2" resultMap="StudentTeacher2">
    select s.id sid, s.name sname, t.name tname
    from mybatis.student s,mybatis.teacher t
    where s.tid = t.id;
</select>

<resultMap id="StudentTeacher2" type="Student">
    <result property="id" column="sid"></result>
    <result property="name" column="sname"></result>
    <association property="teacher" javaType="Teacher">
        <result property="name" column="tname"></result>

    </association>
</resultMap>

一对多处理


按结果嵌套查询

<select id="getTeacher" resultMap="TeacherStudent">
    select s.name sname, s.id sid, t.name tname, t.id tid
    from mybatis.teacher t, mybatis.student s
    where t.id = s.tid and t.id = #{tid};
</select>

<resultMap id="TeacherStudent" type="Teacher">
    <result property="id" column="tid"></result>
    <result property="name" column="tname"></result>
    <!--这里clooection要区别javatype,因为是集合所以用oftype-->
    <collection property="students" ofType="Student">
        <result property="id" column="sid"></result>
        <result property="name" column="sname"></result>
        <result property="tId" column="tid"></result>
    </collection>
</resultMap>

按查询嵌套查询

<select id="getTeacher2" resultMap="TeacherStudent2">
    select * from mybatis.teacher where id = #{tid};
</select>

<resultMap id="TeacherStudent2" type="Teacher">
    <collection property="students" javaType="ArrayList" ofType="Student" column="id" select="getStudentByTeacher"></collection>
</resultMap>

<select id="getStudentByTeacher" resultType="Student">
    select * from mybatis.student where tid = #{tid};
</select>

动态sql


动态sql和jstl标签类似。主要有这几种

  • if
  • choose(when,otherwise)
  • trim(where,set)
  • foreach

if

@Test
public void test1() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    HashMap<String,String> map = new HashMap<String,String>();
    map.put("title","Java");

    List<Blog> blogs = mapper.queryBlogIF(map);
    for (Blog blog : blogs) {
        System.out.println(blog);
    }

    sqlSession.close();
}
//查询博客
List<Blog> queryBlogIF(Map map);
<select id="queryBlogIF" parameterType="map" resultType="blog">
    select * from mybatis.blog where 1=1
    <if test="title != null">
        and title = #{title}
    </if>
    <if test="author != null">
        and author = #{author}
    </if>

</select>

choose(when,otherwise)

在我们使用if标签来拼接sql语句的时候,我们常常使用where 1=1来处理每个语句前面跟着的and的问题。但是这个1=1实际上是没有任何意义的,它只是为了帮助我们去处理掉where后面直接跟着and或者or的问题。使用where标签可以帮助我们去掉1=1这样没有意义的sql语句。

where便签里面正常写if标签的内容即可,只要有一个if成立,那么where语句会自动的插入where,不需要我们写。并且如果where后面紧跟了and或者or这样的关键字,where标签也会帮我们把and或者or去掉

<select id="queryBlogChoose" parameterType="map" resultType="blog">
    select * from mybatis.blog
    <where>
        <if test="title != null">
            title = #{title}
        </if>
        <if test="author != null">
            and author = #{author}
        </if>
    </where>
</select>

choose

<select id="queryBlogChoose" parameterType="map" resultType="blog">
    select * from mybatis.blog where
        <choose>
            <when test="title != null">
                title = #{title}
            </when>
            <when test="author != null">
                author = #{author}
            </when>
            <otherwise>
                views = #{views}
            </otherwise>
        </choose>
</select>

trim(where,set)

set标签会动态的加上set关键字,并且会会帮助我们去掉多余的逗号。在set里写if标签动态的添加sql语句

<update id="updateBlog" parameterType="map">
    update `mybatis`.blog
    <set>
        <if test="title != null">
            title = #{title},
        </if>
        <if test="author != null">
            author = #{author},
        </if>
    </set>
    where id = #{id}
</update>

where和set都有一个父类

<trim prefix=" " prefixOverrides="" suffix="" suffixOverrides=""></trim>

我们可以使用这个父类来定制我们需要的类似set或者where的功能

prefix:需要时自动加上前缀

prefixOverrides:需要时,自动忽略语句前的东西。例如and或者or使用 | 分隔

suffix:需要时自动加上后缀

suffixOverrides:需要时,自动忽略语句后的东西。例如set后面的逗号

SQL片段

<sql id="if-title-author">
    <if test="title != null">
        title = #{title}
    </if>
    <if test="author != null">
        and author = #{author}
    </if>
</sql>

这样的叫做sql片段,在sql语句中使用include包含

<select id="queryBlogWhere" parameterType="map" resultType="blog">
    select * from mybatis.blog
    <where>
        <include refid="if-title-author"></include>
    </where>
</select>

Foreach

<select id="queryBlogForeach" parameterType="map" resultType="blog">
    select * from mybatis.blog
    <where>
        <foreach collection="ids" item="id" separator="or" close=")" open="(">
            id = #{id}
        </foreach>
    </where>
</select>
@Test
public void test3() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    
    HashMap map = new HashMap();
    ArrayList<Integer> ids = new ArrayList<Integer>();
    
    ids.add(1);
    ids.add(2);

    map.put("ids",ids);

    List<Blog> blogs = mapper.queryBlogForeach(map);

    for (Blog blog : blogs) {
        System.out.println(blog);
    }

    sqlSession.close();
}

缓存


存储在内存中的临时数据

如果把我们一次查询到的数据放在内存里面,以后需要的时候去内存调用,这样就可以不用查询数据库了,查询数据库需要IO,IO相对于内存是很慢的。缓存的出现解决了高并发系统的性能问题

经常查询且不经常改变的数据可以使用缓存

mybatis默认有一级缓存和二级缓存

  • 默认一级缓存开启,一级缓存就是sqlsession的缓存
  • 二级缓存需要手动开启或者配置,它是基于namespace级别的缓存
  • 还有接口缓存cache。我们可以通过实现cache接口来自定义二级缓存

一级缓存

缓存失效

  • 增删改会刷新缓存
  • 查询不同的mapper.xml
  • 手动清除缓存

二级缓存

启用二级缓存需要在sql映射文件中添加<cache/>并且要在核心配置文件的setting中开启缓存<setting name="cacheEnabled" value="true"></setting>

二级缓存使用新会话查询的时候,需要实体类序列化,如果实体类没有序列化,那么cache标签需要设置属性readOnly为true

所有缓存数据都会放在一级缓存中,只有当会话关闭或者提交的时候才会提交到二级缓存

缓存原理

自定义缓存-ehcache

要使用它,需要去导包mybatis-ehcache

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">

    <diskStore path="./tmpdir/Tmp_EhCache"/>

    <defaultCache
            eternal="false"
            maxElementsInMemory="10000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="259200"
            memoryStoreEvictionPolicy="LRU"/>

    <cache
            name="cloud_user"
            eternal="false"
            maxElementsInMemory="5000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="1800"
            memoryStoreEvictionPolicy="LRU"/>
</ehcache>

实际工作使用redis更多

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值