Mybatis学习(二)


接上次的mybatis学习

日志

Mybatis提供的日志支持

可选的值有:SLF4J、LOG4J、LOG4J2、JDK_LOGGING、COMMONS_LOGGING、STDOUT_LOGGING、NO_LOGGING,或者是实现了 org.apache.ibatis.logging.Log 接口,且构造方法以字符串为参数的类完全限定名。

mybatis-config.xml文件中配置日志,配置文件必须遵循规范

   <!--数据库外部文件配置-->
    <properties resource="db.properties"/>
    <!--日志配置的位置,必须在properties和typeAliases中间,STDOUT_LOGGING标准的日志工厂实现-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

    <typeAliases>
        <package name="com.itxing.pojo"/>
    </typeAliases>

LOG4J

使用Log4j,可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIXSyslog守护进程等。

可以控制每一条日志的输出格式,控制日志的生成过程

1.导入依赖

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

2.编写配置文件

##Log4J的配置之简单使它遍及于越来越多的应用中了   

##Log4J配置文件实现了输出到控制台、文件、回滚文件、发送日志邮件、输出到数据库日志表、自定义标签等全套功能。择其一二使用就够用了。   

##此文件(log4j.properties)内容来自网络
log4j.rootLogger = DEBUG, console,file 
log4j.addivity.org.apache = true    

# 应用于控制台   
log4j.appender.console = org.apache.log4j.ConsoleAppender   
log4j.appender.console.Threshold = DEBUG   
log4j.appender.console.Target = System.out   
log4j.appender.console.layout = org.apache.log4j.PatternLayout   
log4j.appender.console.layout.ConversionPattern = [framework]  % d  -   % c  -%- 4r [ % t]  %- 5p  % c  % x  -   % m % n   
#log4j.appender.CONSOLE.layout.ConversionPattern = [start] % d  {DATE} [DATE] % n % p[PRIORITY] % n % x[NDC] % n % t[THREAD] n % c[CATEGORY] % n % m[MESSAGE] % n % n   

#应用于文件   
log4j.appender.file = org.apache.log4j.FileAppender   
log4j.appender.file.File = file.log   
log4j.appender.file.Append = false    
log4j.appender.file.layout = org.apache.log4j.PatternLayout   
log4j.appender.file.layout.ConversionPattern = [framework]  % d  -   % c  -%- 4r [ % t]  %- 5p  % c  % x  -   % m % n   
# Use  this  layout  for  LogFactor  5  analysis   

# 应用于文件回滚   
log4j.appender.rolling_file = org.apache.log4j.RollingFileAppender   
log4j.appender.rolling_file.Threshold = ERROR   
log4j.appender.rolling_file.File = rolling.log   
log4j.appender.rolling_file.Append = true    
log4j.appender.rolling_file.MaxFileSize = 10KB   
log4j.appender.rolling_file.MaxBackupIndex = 1    
log4j.appender.rolling_file.layout = org.apache.log4j.PatternLayout   
log4j.appender.rolling_file.layout.ConversionPattern = [framework]  % d  -   % c  -%- 4r [ % t]  %- 5p  % c  % x  -   % m % n   

#应用于socket   
log4j.appender.socket = org.apache.log4j.RollingFileAppender   
log4j.appender.socket.RemoteHost = localhost   
log4j.appender.socket.Port = 5001    
log4j.appender.socket.LocationInfo = true    
# Set up  for  Log Facter  5    
log4j.appender.socket.layout = org.apache.log4j.PatternLayout   
log4j.appender.socket.layout.ConversionPattern = [start] % d  {DATE} [DATE] % n % p[PRIORITY] % n % x[NDC] % n % t[THREAD] % n % c[CATEGORY] % n % m[MESSAGE] % n % n   

# Log Factor  5  Appender   
log4j.appender.LF5_APPENDER = org.apache.log4j.lf5.LF5Appender   
log4j.appender.LF5_APPENDER.MaxNumberOfRecords = 2000    

# 发送日志给邮件   
log4j.appender.mail = org.apache.log4j.net.SMTPAppender   
log4j.appender.mail.Threshold = FATA   
log4j.appender.mail.BufferSize = 10    
log4j.appender.mail.From = web@www.wuset.com   
log4j.appender.mail.SMTPHost = www.wusetu.com   
log4j.appender.mail.Subject = Log4J Message   
log4j.appender.mail.To = web@www.wusetu.com   
log4j.appender.mail.layout = org.apache.log4j.PatternLayout   
log4j.appender.mail.layout.ConversionPattern = [framework]  % d  -   % c  -%- 4r [ % t]  %- 5p  % c  % x  -   % m % n   

# 用于数据库   
log4j.appender.database = org.apache.log4j.jdbc.JDBCAppender   
log4j.appender.database.URL = jdbc:mysql: // localhost:3306/test    
log4j.appender.database.driver = com.mysql.jdbc.Driver   
log4j.appender.database.user = root   
log4j.appender.database.password =    
log4j.appender.database.sql = INSERT INTO LOG4J (Message) VALUES ( ' [framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n ' )   
log4j.appender.database.layout = org.apache.log4j.PatternLayout   
log4j.appender.database.layout.ConversionPattern = [framework]  % d  -   % c  -%- 4r [ % t]  %- 5p  % c  % x  -   % m % n   
log4j.appender.A1 = org.apache.log4j.DailyRollingFileAppender   
log4j.appender.A1.File = SampleMessages.log4j   
log4j.appender.A1.DatePattern = yyyyMMdd - HH ' .log4j '    
log4j.appender.A1.layout = org.apache.log4j.xml.XMLLayout   

#自定义Appender   
log4j.appender.im  =  net.cybercorlin.util.logger.appender.IMAppender   
log4j.appender.im.host  =  mail.cybercorlin.net   
log4j.appender.im.username  =  username   
log4j.appender.im.password  =  password   
log4j.appender.im.recipient  =  corlin@cybercorlin.net   
log4j.appender.im.layout = org.apache.log4j.PatternLayout   
log4j.appender.im.layout.ConversionPattern  = [framework]  % d  -   % c  -%- 4r [ % t]  %- 5p  % c  % x  -   % m % n   

自定义log4j文件

#将等为Debug的日志信息输出到console和file这两个地方
log4j.rootLogger = DEBUG,console,file 

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

#文件输出相关设置   
log4j.appender.file = org.apache.log4j.FileAppender   
#日志文件的路径  
log4j.appender.file.File = ./log/itxing.log
log4j.appender.file.Append = false    
log4j.appender.file.layout = org.apache.log4j.PatternLayout   
log4j.appender.file.layout.ConversionPattern = [%p][%d{yyyy-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

3.配置log4j为日志的实现

<!--将std实现转换成log4j实现-->
    <settings>
        <setting name="logImpl" value="LOG4J"/>
    </settings>

4.简单使用log4j

使用Logger类需要导入,import org.apache.log4j.Logger;

日志级别:ERROR、WARN、INFO、DEBUG

分页:

1.使用limit分页

select * from user limit startIndex,pagesize

2.使用mybatis分页:使用万能的参数map,将参数传递到dao查询

    <select id="getUserLimit" parameterType="map"         resultType="com.itxing.pojo.User">
        select  * from test.user limit #{startIndex},#{pageSize}
    </select>

java类中使用map传参

    //测试分页查询
    @Test
    public void getUserLimit(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        Map<String,Integer> map = new HashMap<String,Integer>();
        map.put("startIndex",0);
        map.put("pageSize",2);
        List<User> userLimit = mapper.getUserLimit(map);
        for (User user : userLimit) {
            System.out.println(user);
        }
          sqlSession.close();
    }

3.面向对象实现分页,使用一个对象RowBounds

 <!--使用面向对象实现分页-->
    <select id="getUserLimitByObj"   resultType="com.itxing.pojo.User">
        select  * from test.user
    </select>
 @Test
    public void getUserByObj(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        RowBounds row = new RowBounds(1,2);
        List<User> objects = sqlSession.selectList("com.itxing.dao.UserMapper.getUserLimitByObj",null,row);
        for (User object : objects) {
            System.out.println(object);
        }
      sqlSession.close();
    }

4.使用分页插件PageHelper

插件官网

注解开发: 主要是为了让解耦

注解的接口:,在接口方法上写上sql,适用于简单的增删改查操作,对于复杂的sql最好使用配置进行

/**
 * @author xing
 * @create 2020/5/19-mybatis
 */
public interface ProductMapper {
    //查询注解,获取所有的产品信息
    @Select("select * from test.product")
    List<Product> getProductAll();

    //条件查询注解
    //@Param基本类型或者String类型,需要加上注解,引用类型不需要加
    //如果只有一个基本类型的话,可忽略,sql中的引用就是@Param中设定的属性名
    @Select("select * from test.product where pid = #{pid}")
    Product getProductById(@Param("pid") int pid);

    //插入数据注解
    @Insert("insert into test.product(pid,pname,pprice,pcategary) values(#{pid},#{pname},#{pprice},#{pcategary})")
    int addProduct(Product product);
}

底层原理是反射技术、动态代理。代理模式、工厂模式、单例模式

修改工具类,使得能够对事物进行设置

/**
 * @author xing
 * @create 2020/5/18-mybatis
 */
public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    static{
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
             sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //有sqlSessionFactory就从工厂中获取SqlSession的实例
    //SqlSession完全包含了面向数据库执行sql命令所需的所有方法
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
    //设置参数开启事务,最好不适用自动提交事务,自己的代码应try捕获异常
    //有sqlSessionFactory就从工厂中获取SqlSession的实例
    //SqlSession完全包含了面向数据库执行sql命令所需的所有方法
    public static SqlSession getSqlSession(boolean flag){
        return sqlSessionFactory.openSession(flag);
    }
}

lombok插件:

 <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
            <scope>provided</scope>
        </dependency>

lombok常用注解:

@Data 自动生成get/set
@NoArgsConstructor 无参构造函数
@ToString toString方法
@AllArgsConstructor 全参数构造函数

Mybatis复杂查询

多对一和一对多,站在不同的角度。再提resultMap

resultMap元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets数据提取代码中解放出来,并在一些情形下允许你进行一些JDBC 不支持的操作。实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份 resultMap能够代替实现同等功能的数千行代码。

建立复杂查询关联表:学生表和教师表,一个老师对应对个学生,测试使用的表


##生成一张教师表
CREATE TABLE `teacher`(
    `id` INT(10) NOT NULL,
    `name` VARCHAR(30) DEFAULT NULL,
    PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
###插入教师数据
INSERT INTO `teacher`(`id`,`name`) VALUES(1,'xing');

#生成一张学生表,关联老师
CREATE TABLE `student`(
    `id` INT(10) NOT NULL,
    `name` VARCHAR(30) DEFAULT NULL,
    `tid` INT(10) DEFAULT NULL,
    PRIMARY KEY(`id`),
    KEY `fktid` (`tid`),
    CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
)ENGINE = INNODB DEFAULT CHARSET=utf8;
##插入多个学生
INSERT INTO `student`(`id`,`name`,`tid`) VALUES (1,'小一',1);
INSERT INTO `student`(`id`,`name`,`tid`) VALUES (2,'小二',1);
INSERT INTO `student`(`id`,`name`,`tid`) VALUES (3,'小三',1);
INSERT INTO `student`(`id`,`name`,`tid`) VALUES (4,'小四',1);
INSERT INTO `student`(`id`,`name`,`tid`) VALUES (5,'小五',1);

1.多对一处理

方式一:创建对应的实体类(方式一相当于两步进行操作,第一步先将学生查询出来,第二步根据学生查询出来的结果查询外键关联的表)

/**
 * @author xing
 * @create 2020/5/20-mybatis
 */
@Data
@NoArgsConstructor
@ToString
public class Student {
    int id;
    String name;
    //学生关联老师,对应的老师类型
    Teacher teacher;
}
/**
 * @author xing
 * @create 2020/5/20-mybatis
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Teacher {
    int id;
    String name;
}

编写对应的配置文件

主配置文件中为两个实体类配置别名

 <typeAliases>
        <typeAlias type="com.itxing.pojo.Teacher" alias="Teacher"></typeAlias>
        <typeAlias type="com.itxing.pojo.Student"   alias="Student"></typeAlias>
    </typeAliases>

Student对应的mapper配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itxing.dao.StudentMapper">
   <!--首先查询响应的学生,根据学生的tid查询老师
    查询结果进行结果集映射,学生中的教师信息使用association进行映射,将根据结果集中的id进行教师信息查询
    -->
    <select id="getStudentList" resultMap="StudentTeacher">
        select * from test.student
    </select>
  <resultMap id="StudentTeacher" type="Student">
      <result property="id" column="id"></result>
      <result property="name" column="name"></result>
      <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"> </association>
  </resultMap>
    <select id="getTeacher" resultType="Teacher">
        select * from test.teacher where id = #{id}
    </select>
</mapper>

Teacher对应的配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--configuration核心配置文件-->
<mapper namespace="com.itxing.dao.TeacherMapper">

</mapper>

查询学生学生中包含有对应的教师字段:

    @Test
    public void getStudent(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
           //查询学生,以及其对应的老师信息
        List<Student> studentList = mapper.getStudentList();
        for (Student student : studentList) {
            System.out.println(student);

        }
          sqlSession.close();
    }

方式二:按照结果嵌套处理(联合查询)

学生的配置文件中,一个sql先将表中的所有关系查询出来在进行结果映射

 <!--方式二,查询学生-->
    <select id="getStudent2" resultMap="StudentTeacher2">
        select s.id sid,s.name sname,t.name tname from test.student s,test.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>

2.一对多,一个老师对应多个学生,需要在老师表中添加外键

方式一:一条sql查询老师下的所有学生

@Data
@NoArgsConstructor
@ToString
public class Student {
    int id;
    String name;
    //学生关联老师,一对多时只是存放教师的id
    int tid;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Teacher {
    int id;
    String name;
    //一对多,一个老师对应多个学生,使用一个集合
    List<Student> student;
}

主配置文件不变,student和teacher配置文件不同

<!--教师的配置文件中的配置,一条sql语句将记录查询出来在进行map映射-->   
<select id="getTeacher2" resultMap="TeacherStudent">
        select t.id tid,t.name tname,s.name sname
from test.teacher t,test.student s where t.id = s.tid
    </select>
    <resultMap id="TeacherStudent" type="Teacher">
        <result property="id" column="tid"></result>
        <result property="name" column="tname"></result>
        <!--
        多对一使用的是对象 association 一对多使用的是collection
        javaType="Student"指定属性类型
        集合中使用泛型信息 ofType指定类型
        -->
        <collection property="student" ofType="Student">
            <result property="name" column="sname"></result>
        </collection>
    </resultMap>

测试类:

  @Test
    public void testOneToMore(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        List<Teacher> teacher2 = mapper.getTeacher2();
        for (Teacher teacher : teacher2) {
            System.out.println(teacher);
        }
        sqlSession.close();
    }

方式二:先将教师查询出来再去查询对应的学生信息,一对多使用的是collection

<select id="getTeacher3" resultMap="TeacherStudent2">
        select * from test.teacher where id=#{tid}
    </select>
    <resultMap id="TeacherStudent2" type="Teacher">
        <!--collection中property是Teacher类中的学生字段,javaType是对应属性的类型,集合类型的实现类型,ofType是集合的泛型约束类型,select表示再次进行查询-->
        <collection property="student" javaType="ArrayList" ofType="Student" select="getStudentByTeacherId" column="id"></collection>
    </resultMap>
    <select id="getStudentByTeacherId" resultType="Student">
        select * from student where tid = #{tid}
    </select>

测试类:

   @Test
    public  void selectTeacherByid(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        List<Teacher> teacher3 = mapper.getTeacher3(1);
        for (Teacher teacher : teacher3) {
            System.out.println(teacher);
        }
    }

注:多对一:association 一对多collection

javaType表示实体类的属性类型 和ofType表示集合类的泛型中的约束类型

动态sql

根据不同的条件生成不同的sql语句,获取不同的数据

测试的数据库文件

CREATE TABLE `blog`(
    `id` VARCHAR(50) NOT NULL ,
    `title` VARCHAR(100)NOT NULL,
    `author` VARCHAR(30) NOT NULL,
    `create_time` DATETIME NOT NULL ,
    `views` INT(30) NOT NULL
)ENGINE = INNODB DEFAULT CHARSET = utf8;

INSERT INTO blog(id,title,author,create_time,views) VALUES('1','nihao','itxing','2020-05-20',10)

解决数据库字段与实体类命名不一致,最好使用驼峰命名规则

   <settings>
        <!--设置日志-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <!--开启驼峰命名规则-->
        <setting name="mapUnderscoreToCameCase" value="true"></setting>
    </settings>

对应的实体类

/**
 * @author xing
 * @create 2020/5/20-mybatis
 */
@Data
@NoArgsConstructor
@ToString
@AllArgsConstructor
public class Blog {
    private String id;
    private String title;
    private String author;
    //数据库的字段为 create_time,使用驼峰命名转换
    private Date createTime;
    private int views;
}

动态sql之if,在blogmapper.xml中配置

    <!--条件查询-->
    <select id="queryBlogIF" parameterType="map" resultType="Blog">
        select * from test.blog where 1=1
        <if test="title != null">
            and title = #{title}
        </if>
        <if test="author!=null">
            and author = #{author}
        </if>
    </select>
<!--或则使用where标签,上面与下面的功能一致,使用一种即可-->
 <!--条件查询-->
    <select id="queryBlogIF" parameterType="map" resultType="Blog">
        select * from test.blog
        <where>
            <!--每一个都加入标签就算只有第一个有值,会变成where and mybatis会将第一个and去掉保证sql正确-->
            <if test="title != null">
                and title = #{title}
            </if>
            <if test="author!=null">
                and author = #{author}
            </if>
        </where>
    </select>

choose(when、where)

  <!--choose和when相当于java中的switch case语句-->
    <select id="queryBlogChoose" parameterType="map" resultType="Blog">
        select * from test.blog
        <where>
            <choose>
                <when test="title != null">
                    title=#{title}
                </when>
                <when test="author != null">
                    and  author=#{author}
                </when>
                <otherwise>
                    and views=#{views}
                </otherwise>
            </choose>
        </where>
    </select>

trim、where、set

<!--set标签,会自动将中间的set之后的参数“,”去掉-->
    <update id="updateBlog" parameterType="map">
        update blog
       <set>
           <if test="title != null">
               title = #{title},
           </if>
           <if test="author !=null">
               author = #{author},
           </if>
       </set>
        where id = #{id}
    </update>

抽取公共部分

    <!--使用sql标签以及include便签将可以重用的程序抽取出来-->
    <sql id="if_title_author">
        <if test="title != null">
            title = #{title}
        </if>
        <if test="author!=null">
            and author = #{author}
        </if>
    </sql>
    <!--条件查询-->
    <select id="queryBlogIF" parameterType="map" resultType="Blog">
        select * from test.blog
        <where>
            <include refid="if_title_author"></include>
        </where>
    </select>
      <!--修改对象-->
    <update id="updateBlog" parameterType="map">
        update blog
        <set>
            <include refid="if_title_author"></include>
        </set>
        where id = #{id}
    </update>

foreach部分查询,动态拼接出来sql语句

<!--SELECT * FROM test.blog WHERE 1=1 AND (id=1 OR id = 2 OR id = 5)进行xml配置中时,传入参数为map将map中传入一个id集合的,循环遍历集合将数据填入拼接sql语句
-->
 <select id="queryBlogForeach" parameterType="map" resultType="Blog">
        select  * from test.blog
        <where>
            <foreach collection="ids" item="id" open="and (" close=")" separator="or">
              id = #{id}
            </foreach>
        </where>
    </select>

mybatis缓存:

1.缓存是存在内存中的临时的数据,将用户经常查询的数据放在缓存中,用户去查询数据就不用从磁盘上查询,从缓存中查询,从而提高效率,一定程度上解决高并发系统的性能问题。

2.使用缓存减少用户和数据库的交互次数,减少系统的消耗,提高系统的效率

3.适合使用缓存的是经常查询且不经常改变的数据

Mybatis中默认开启以及缓存,Sqlsession级别称为本地缓存,二级缓存需要手动的开启,基于namespace级别的缓存。

缓存清理策略:

LRU:最近最少使用过期策略

FIFO:先进先出

SOFT:软引用

WEAK:虚引用

在同一个Sqlsession中查询同一个语句执行一次,查询不同的语句查询两次,以及缓存默认开启,不能关闭在同一个SqlSession中有效可以手动清理缓存,增删改对数据库进行写操作的时候一定会刷新缓存

//不清理缓存时,默认开启一级缓存,查询相同的语句只执行一次,只在一次SqlSession中有效  
@Test
    public void testQuery(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user1 = mapper.queryUserById(1);
//        sqlSession.clearCache();
        User user2 = mapper.queryUserById(1);
        System.out.println(user1);
        System.out.println(user2);
        sqlSession.close();
    }

image-20200522120012052

清理以及缓存将sqlSession.clearCache()代码开启,执行结果会有两次与数据库交互。

image-20200522120305793

xml中设置缓存的参数:xml文件的设置参数

  <!--配置日志,必须放在pro和set之间-->
    <settings>
        <!--设置日志-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <!--开启驼峰命名规则-->
        <setting name="mapUnderscoreToCamelCase" value="true"></setting>
        <!--配置二级缓存-->
        <setting name="cacheEnabled" value="true"></setting>
    </settings>

缓存常用参数设置:

<!--缓存算法先进先出,大小为512-->  
<cache eviction="FIFO"  
         flushInterval="60000"
         size="512" 
         readOnly="true"></cache>

二级缓存的测试,两次查询使用两个sqlSession回话

  @Test
    public void testQueryCache(){
        //创建两个SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        SqlSession sqlSession2 = MybatisUtils.getSqlSession();
        //第一个回话查询用户1
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user1 = mapper.queryUserById(1);
        System.out.println(user1);
        sqlSession.close();
        //第二个回话查询用户1
        UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
        User user2 = mapper2.queryUserById(1);
        System.out.println(user2);
        sqlSession2.close();
    }

在缓存时,需要将对象进行实例化。

Ehcache自定义缓存,导入依赖,添加配置

   <dependencies>
        <dependency>
            <groupId>org.mybatis.caches</groupId>
            <artifactId>mybatis-ehcache</artifactId>
            <version>1.1.0</version>
        </dependency>
    </dependencies>

创建一个ehcache.xml的文件

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

    <diskStore path="./tmpdit/Tmp_Ehcache"/>

    <!--
    Mandatory Default Cache configuration. These settings will be applied to caches
    created programmtically using CacheManager.add(String cacheName)
    -->
    <!--
       name:缓存名称。
       maxElementsInMemory:缓存最大个数。
       eternal:对象是否永久有效,一但设置了,timeout将不起作用。
       timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
       timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
       overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。
       diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
       maxElementsOnDisk:硬盘最大缓存个数。
       diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
       diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
       memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
       clearOnFlush:内存数量最大时是否清除。
    -->
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
            maxElementsOnDisk="10000000"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"
    />
</ehcache>

在mapper.xml中使用

<!--也可以使用自定义的缓存-->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>

总结:

注意点:mapper绑定文件时,需要注意使用resource可以在任何位置,使用class时需要保证mapper接口与mapper.xml配置在同一包下

mybatis中的重点包括分页、mybatis二级缓存、动态sql(if、foreach、choose、when、trim)等、#{}表示预编译处理和${}字符串替换。mybatis中的一对多和多对一,以及懒加载(只有关联对象时支持懒加载)、mybatis的好处以及和hibernate的区别。

mybatis与hibernate不同

1.hibernate是一个ORM框架,不需要写sql语句,mybatis需要程序员自己写sql语句,
mybatis通过XML或注解形式灵活配置运行sql语句,将sql执行的结果映射成java对象
2.mybits易学,程序员直接编写原生的sql,适合对关系数据模型要求不高的软件开发,
但是对于不同的数据库,hibernate可以无关数据库
3.hibernate对象/关系映射能力强,数据库无关性好,可以节省很多代码.总之,按照要求的框架,维护性、扩展性良好的软件框架都是好框架xml文件使用命名空间与接口文件进行绑定使用原始的dao接口等进行开发,需要自己传入sqlSessionFactory,每个dao方法中需要自己手动获取opensession对象。

mybatis配置文件的参数顺序是固定的。

mappers映射器:

1.使用resource寻找对应的xml文件,寻找sql语句文件,再找到接口文件
2.使用class类型声明时,只能填写mapper接口类,必须要遵循原则使用同名称的文件名(接口文件与xml文件的类名相同)且在同一包下
3.使用url指定路径,但是必须使用物理路径(不适用)


文章作者: it星
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 it星 !
 上一篇
mysql语句相关学习 mysql语句相关学习
it星
mysql语句训练:mysql官网 1. mysql数据库创建表语句--商品表 CREATE TABLE product_info ( product_id VARCHAR(32) NOT NULL, product_na
2020-05-20
下一篇 
WebService客户端调用 WebService客户端调用
Webservice调用接口: Web Service是一个平台独立的,低耦合的,自包含的、基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)标准来描述、发布、发现、协调和配置这些应用程序,用于开发分布式的交
  目录