day51_mybatis

今日内容

零、 复习昨日
一、缓存
二、单例设计模式

零、 复习昨日

多表联查的时候

  • 扩展类
  • 写接口设计方法
  • 写sql语句
    • 不能直接映射成实体类
    • resultMap
      • 一对一 axxxxxxx
      • 一对多 collection

一、$和#的区别

使用#

day51_mybatis_第1张图片

使用$

day51_mybatis_第2张图片

总结:

#{} 相当于是预处理语句,会将#换成占位符?,字符串等数据赋值时自动拼接引号,可以避免SQL注入

${} 相当于是处理语句,直接原样将数据取出,直接拼接

使用模糊查询再验证一遍

使用#{} 写模糊查询

    <select id="findByKeyword" resultType="User">
        
        select * from tb_user where username like '%#{keyword}%' 
    select>

以上写法会把sql变成这样,#符号会给字符串拼接单引号

select * from tb_user where username like ‘%‘张’%’

改成${}写模糊查询

    <select id="findByKeyword" resultType="User">
        
        select * from tb_user where username like '%${keyword}%' 
    select>

以上写法会把sql变成这样,$符号是直接取值的

select * from tb_user where username like ‘%张%’

函数concat解决#{} 拼接单引号问题

<select id="findByKeyword" resultType="User">
    
    select * from tb_user where username like concat('%',#{keyword},'%')
select>

二、缓存(cache)【面试问】

缓存主要目的是为了提高查询效率.缓存其实就是一个内存空间,存储在程序的某个地方,存储数据.

mybatis支持缓存的,且有两级缓存

  • 一级缓存
  • 二级缓存
无缓存:用户在访问相同数据时,需要发起多次对数据库的直接访问,导致产生大量IO、读写硬盘的操作,效率低下
day51_mybatis_第3张图片
有缓存:首次访问时,查询数据库,将数据存储到缓存中;再次访问时,直接访问缓存,减少IO、硬盘读写次数、提高效率
day51_mybatis_第4张图片

2.1 一级缓存

MyBatis的一级缓存是默认的.无需配置,自动实现.

默认的一级缓存是SqlSession级别,是指同一个SqlSession发起的多次查询同一条数据,会使用缓存.

day51_mybatis_第5张图片

ps: Mybatis内部存储缓存使用的是一个HashMap对象,key为 hashCode + sqlId + sql 语句。而value值就是从查询出来映射生成的java对象。

2.1.1 命中缓存

    /**
     * 测试一级缓存
     * -----------------------
     * 如何确定使用了缓存而不是查询数据库? 通过sql语句来确定
     * 只有发出sql,就说明查询数据库,即没有用缓存
     */
    @Test
    public void testOneLevelCache() {
        UserMapper mapper1 = sqlSession.getMapper(UserMapper.class);
        User user1 = mapper1.findUserById(1);
        System.out.println("user1 = " + user1);

        System.out.println("-----------------------");
        // 命中缓存的前提:1) 同一SqlSession,2) 同一条件
        UserMapper mapper2 = sqlSession.getMapper(UserMapper.class);
        User user2 = mapper2.findUserById(1);
        System.out.println("user2 = " + user2);
    }

day51_mybatis_第6张图片

2.1.2 不使用缓存的情况

不使用缓存的情况1: 条件不一致

day51_mybatis_第7张图片

不使用缓存的情况2: sqlSession不一样

   @Test
    public void testOneLevelCache2() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        // 获得会话1
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
        User user1 = mapper1.findUserById(1);
        System.out.println("user1 = " + user1);

        System.out.println("---------------------------------" );
        // 获得一个会话2
        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
        User user2 = mapper2.findUserById(1);
        System.out.println("user2 = " + user2);
    }

day51_mybatis_第8张图片

虽然是同一条数据,但是还是没有使用缓存!为什么?

一级缓存是SqlSession级别,即缓存数据存储在SqlSession中,这次都不是同一个SqlSession,那就无法使用缓存

2.1.3 清空缓存

在更新(更新,删除,插入)数据后,会清空缓存,下次重新查最新的数据.避免脏读

   /**
     * 演示: 增删改都会清空缓存
     */
    @Test
    public void testOneLevelCache3() {
        UserMapper mapper1 = sqlSession.getMapper(UserMapper.class);
        User user1 = mapper1.findUserById(1);
        System.out.println("user1 = " + user1);
        System.out.println("---------------------------------" );

        // 只要有增删改都会清空缓存
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = new User( );
        user.setId(2);
        user.setUsername("QF");
        user.setPassword("qf888");
        int i = mapper.updateUser(user);
        System.out.println(i > 0?"OK":"ERR" );
        // 增删改要提交
        sqlSession.commit();


        System.out.println("---------------------------------" );
        // 清空缓存后,再查就要从数据库查
        UserMapper mapper2 = sqlSession.getMapper(UserMapper.class);
        User user2 = mapper2.findUserById(1);
        System.out.println("user2 = " + user2);
    }

day51_mybatis_第9张图片

2.1.4 关闭缓存

一级缓存也叫本地缓存(LocalCache),Mybatis的一级缓存是会话级别(SqlSession)层面进行缓存的。Mybatis的一级缓存是默认开启的。开发项目中不需要做任何配置,但是如果想关闭一级缓存,可以在mybatis配置文件的settings下面使用localCacheScopde=statement来关闭。

<settings>
    
    <setting name="localCacheScope" value="STATEMENT"/>
settings>

2.2 二级缓存

二级缓存是Mapper级别,比SqlSession级别范围更大.

使用时需要手动设置

  • 1)需要在全局配置文件中开启缓存(默认开着的)

        <settings>
            
            <setting name="cacheEnabled" value="true"/>
        settings>
    
  • 2)需要在mapper中设置caceh即可

    <cache/>
    
    • 映射语句文件中的所有 select 语句的结果将会被缓存。
    • 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。

2.2.1 使用二级缓存

  • 1)需要在全局配置文件中开启缓存(默认开着的)
  • 2)需要在mapper中设置caceh即可
  • 3)每个会话执行完,要关流close,才会将查询是数据放入缓存
  • 4)实体类需要系列化,实现Serializable接口
   /**
     * 二级缓存
     * 演示不同SqlSession,会命中缓存
     */
    @Test
    public void testTwoLevelCache1() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        // 获得会话1
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
        User user1 = mapper1.findUserById(1);
        System.out.println("user1 = " + user1);
        // 关闭会话,才会将这次查询的结果放入缓存!!!
        sqlSession1.close();


        System.out.println("---------------------------------" );
        // 获得一个会话2
        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
        User user2 = mapper2.findUserById(1);
        System.out.println("user2 = " + user2);
        sqlSession2.close();


        System.out.println("---------------------------------" );
        // 获得一个会话3
        SqlSession sqlSession3 = sqlSessionFactory.openSession();
        UserMapper mapper3 = sqlSession3.getMapper(UserMapper.class);
        User user3 = mapper3.findUserById(1);
        System.out.println("user3 = " + user3);
        sqlSession3.close();
    }

day51_mybatis_第10张图片

2.2.2 清空缓存

   /**
     * 二级缓存
     * 演示增删改会清空缓存
     */
    @Test
    public void testTwoLevelCache2() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        // 获得会话1
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
        User user1 = mapper1.findUserById(1);
        System.out.println("user1 = " + user1);
        // 关闭会话,才会将这次查询的结果放入缓存!!!
        sqlSession1.close();


        System.out.println("---------------------------------" );
        // 获得一个会话2
        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
        User user2 = mapper2.findUserById(1);
        System.out.println("user2 = " + user2);
        System.out.println("---------------------------------" );

        // 只要有增删改都会清空缓存
        UserMapper mapper = sqlSession2.getMapper(UserMapper.class);
        User user = new User( );
        user.setId(2);
        user.setUsername("QF");
        user.setPassword("qf888");
        int i = mapper.updateUser(user);
        System.out.println(i > 0?"OK":"ERR" );
        // 增删改要提交
        sqlSession2.commit();
        sqlSession2.close();

        System.out.println("---------------------------------" );
        // 获得一个会话3
        SqlSession sqlSession3 = sqlSessionFactory.openSession();
        UserMapper mapper3 = sqlSession3.getMapper(UserMapper.class);
        User user3 = mapper3.findUserById(1);
        System.out.println("user3 = " + user3);
        sqlSession3.close();
    }

day51_mybatis_第11张图片

day51_mybatis_第12张图片

三、整合数据源

引入依赖

        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>druidartifactId>
            <version>1.2.8version>
        dependency>

配置db.properties文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/database_name?useSSL=false
jdbc.username=root
jdbc.password=123456
jdbc.initialSize=5
jdbc.maxActive=20
jdbc.minIdle=3
jdbc.maxWait=0
jdbc.timeBetweenEvictionRunsMillis=0
jdbc.minEvictableIdleTimeMillis=0

替换原有的连接池类型

需要创建一个类,继承Mybatis提供一个数据库连接池的工厂类

package com.qf.util;

import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.datasource.pooled.PooledDataSourceFactory;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
public class MyDruidDataSourceFactory extends PooledDataSourceFactory {
    // 构造方法
    public MyDruidDataSourceFactory(){
        // 创建alibaba的连接池
        this.dataSource = new DruidDataSource();
    }
}
<environments default="development">
    <environment id="development">
        <transactionManager type="JDBC"/>
        
        <dataSource type="com.qf.util.MyDruidDataSourceFactory">
            
            
            
            <property name="driverClass" value="${jdbc.driver}"/>
            <property name="jdbcUrl" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
        dataSource>
    environment>
environments>

后续正常使用CRUD,可以减少查询时间.

四、逆向工程(神器)

只有给定数据库表,然后逆向工程可以直接根据表自动生成实体类,接口文件,CRUD方法以及对应的映射文件,以及文件中写好SQL语句.

1 加入逆向工程的依赖

    <dependencies>
        <dependency>
            <groupId>org.mybatis.generatorgroupId>
            <artifactId>mybatis-generator-coreartifactId>
            <version>1.3.5version>
        dependency>

        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>5.1.47version>
        dependency>
    dependencies>

2 pom中加入逆向工程的插件

<build>
    <plugins>
        <plugin>
            <groupId>org.mybatis.generatorgroupId>
            <artifactId>mybatis-generator-maven-pluginartifactId>
            <version>1.3.5version>
            
            <configuration>
                <configurationFile>src\main\resources\generator.xmlconfigurationFile>
                <verbose>trueverbose>
                <overwrite>trueoverwrite>
            configuration>
            <dependencies>
                <dependency>
                    <groupId>mysqlgroupId>
                    <artifactId>mysql-connector-javaartifactId>
                    <version>5.1.47version>
                dependency>
            dependencies>
        plugin>
    plugins>
build>

3 编写逆向所需配置文件


DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <context id="testTables" targetRuntime="MyBatis3">
        
        <plugin type="org.mybatis.generator.plugins.ToStringPlugin"/>

        <commentGenerator>
            
            <property name="suppressAllComments" value="true"/>
        commentGenerator>
        
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/java2212"
                        userId="root"
                        password="123456">
        jdbcConnection>

        
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false"/>
        javaTypeResolver>

        
        <javaModelGenerator targetPackage="com.qf.model"
                            targetProject=".\src\main\java">
            
            <property name="enableSubPackages" value="false"/>
            
            <property name="trimStrings" value="true"/>
        javaModelGenerator>
        
        <sqlMapGenerator targetPackage="com.qf.mapper"
                         targetProject=".\src\main\java">
            
            <property name="enableSubPackages" value="false"/>
        sqlMapGenerator>
        
        <javaClientGenerator type="XMLMAPPER"
                             targetPackage="com.qf.mapper"
                             targetProject=".\src\main\java">
            
            <property name="enableSubPackages" value="false"/>
        javaClientGenerator>
        <table tableName="admin"
               enableCountByExample="false"
               enableUpdateByExample="false"
               enableDeleteByExample="false"
               enableSelectByExample="false"
               selectByExampleQueryId="false"/>
        <table tableName="user"
               enableCountByExample="false"
               enableUpdateByExample="false"
               enableDeleteByExample="false"
               enableSelectByExample="false"
               selectByExampleQueryId="false"/>
    context>
generatorConfiguration>

4 运行

day51_mybatis_第13张图片

五、单例设计模式

确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。

单例模式是一种对象创建型模式。

Servlet默认是单例的。

单例模式有三个要点:

  • 某个类只能有一个实例
  • 它必须自行创建这个实例
  • 它必须自行向整个系统提供这个实例。

懒汉式

(1)由于每次使用new关键字来实例化Singleton 类时都将产生一个新对象,为了确保Singleton 实例的唯一性,我们需要禁止类的外部直接使用new来创建对象,因此需要将Singleton 的构造函数的可见性为private

(3)为了保证成员变量的封装性,我们将Singleton 类型的single的可见性设置为private,但外界该如何使用该成员变量并何时实例化该成员变量呢?答案是增加一个公有的静态方法Singleton getInstance(),

//懒汉式单例类.在第一次调用的时候实例化自己   
public class Singleton {  
    //1 私有的构造器
    private Singleton() {}  
    //2 私有 静态 Singleton类型 成员变量
    private static Singleton single=null;  
    //3 公有静态方法  
    public static Singleton getInstance() {  
         if (single == null) {    
             single = new Singleton();  
         }    
        return single;  
    }  
}

饿汉式

不管有么有被被人使用,先把对象创建出来

//饿汉式单例类.在类初始化时,已经自行实例化   
public class Singleton1 {  
    //1 私有构造器
    private Singleton1() {} 
    //2 直接创建私有 静态(可以不是final)对象
    private static final Singleton1 single = new Singleton1();  
    //3 静态方法   
    public static Singleton1 getInstance() {  
        return single;  
    }  
}  

你可能感兴趣的:(#,Java2307,mybatis,java,开发语言)