1:关联查询

一对一

<association fetchType="lazy" property="employeeCard" column="id" select="com.mybatis.mybatisdemo.mapper.EmployeeCardMapper.selectByPrimaryKey" ></association>

一对多

<collection property="projectList" column="id" select="com.mybatis.mybatisdemo.mapper.ProjectMapper.finfAllById" fetchType="lazy"></collection>

标签说明:

fetchType:开启懒加载。开启时只会查询基本信息,当需要用到关联信息时自动触发查询,取出需要的数据。

property:对象属性,即查询出的关联信息映射到哪个属性中。

column:代表SQL的列,用作参数传递给select标签,用作查询是的参数,如果是多参数用逗号隔开

select:需要执行语句的命名空间,家接口名称

多对多(3张表)

拆分为两个一对多的关系,也就是一个角色对应多个用户,一个用户对用多个角色,

<collection property="projectList" column="id" select="com.mybatis.mybatisdemo.mapper.ProjectMapper.finfAllById"></collection>
//根据用户ID获取该用户下的工程集合(关联用户工程的关联表) 
@Select("select p.id , p.proj_name projName  from t_project p join t_employee_project ep on p.id =ep.proj_id  where ep.emp_id = #{empId}")
List<Project> finfAllById(@Param("empId") Integer empId);

<collection property="employeesList" column="id" select="com.mybatis.mybatisdemo.mapper.EmployeeMapper.findAllByProId"></collection>
//根据工程Id获取该工程下的用户集合(关联用户工程的关联表)
@Select("select e.id , e.emp_name as empName ,e.sex from t_employee e ,t_employee_project ep where e.id=ep.emp_id and ep.proj_id = #{proId} ")
List<Employee> findAllByProId(Integer proId);

2:缓存

一级缓存是在SqlSession上的缓存,默认开启,只有相同的SqlSession才能获取缓存数据。

二级缓存:因为一级缓存是在SqlSession层面的,对于不同层面的SqlSession对象是不能共享的,为了使SqlSession对象之间能共享相同的缓存,需要开启二级缓存,开启二级缓存很简单,

1:只要在映射文件mapper.xml上添加标签。

2:对实体类对象序列化,反序列化实现Serializable接口,如果没有时间Serializable接口MyBatis将会抛出异常。

4:二级缓存整合Redis插件

POM

<!--Redis-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--spring2.0集成redis所需common-pool2-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

.yml

spring:
  redis:
    host: 127.0.0.1
    port: 6379
    lettuce:
      pool:
        max-active: 8
        max-wait: -1
        max-idle: 8
        min-idle: 0
mybatis:
  mapper-locations: "classpath:myBatis/*.xml"
  configuration:
    cache-enabled: true
  type-aliases-package: com.mybatis.mybatisdemo.entity

Redis配置类设置数据库存入redis时的K,V的序列化方式

@Configuration
public class RedisConfig {

   @Autowired
   private LettuceConnectionFactory connectionFactory;

   @Bean
   public RedisTemplate<String,Object> redisTemplate() {
      RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
      initDomainRedisTemplate(redisTemplate, connectionFactory);
      return redisTemplate;
   }

   /**
    * 设置数据存入 redis 的序列化方式
    * @param template
    * @param factory
    */
   private void initDomainRedisTemplate(RedisTemplate<String, Object> template,LettuceConnectionFactory factory) {
      // 定义 key 的序列化方式为 string
      // 需要注意这里Key使用了 StringRedisSerializer,那么Key只能是String类型的,不能为Long,Integer,否则会报错抛异常。
      StringRedisSerializer redisSerializer = new StringRedisSerializer();
      template.setKeySerializer(redisSerializer);
      // 定义 value 的序列化方式为 json
      @SuppressWarnings({"rawtypes", "unchecked"})
      Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
      ObjectMapper om = new ObjectMapper();
      om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
      om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
      jackson2JsonRedisSerializer.setObjectMapper(om);
      template.setValueSerializer(jackson2JsonRedisSerializer);

      //hash结构的key和value序列化方式
      template.setHashKeySerializer(jackson2JsonRedisSerializer);
      template.setHashValueSerializer(jackson2JsonRedisSerializer);
      template.setEnableTransactionSupport(true);
      template.setConnectionFactory(factory);
   }

}

使用Redis来做Mybatis的二级缓存实现Mybatis的Cache接口

public class MybatisRedisCache implements Cache {

    private static final Logger log = LoggerFactory.getLogger(MybatisRedisCache.class);
    private String id;
    private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    //private static final long EXPIRE_TIME_IN_MINUTES = 30; // redis过期时间


    public MybatisRedisCache(String id) {
        this.id = id;
    }

    /**
     * 获取 redisTemplate 对象 手动调用ApplicationContextHolder类中geyBean()方法获取
     * @return
     */
    private RedisTemplate<Object, Object> getRedisTemplate(){
        return ApplicationContextHolder.getBean("redisTemplate");
    }

    @Override
    public String getId() {
        return id;
    }

    @Override
    public void putObject(Object key, Object value) {
        RedisTemplate redisTemplate = getRedisTemplate();
        redisTemplate.boundHashOps(getId()).put(key, value);
        log.info("[结果放入到缓存中: " + key + "=" + value+" ]");

    }

    @Override
    public Object getObject(Object key) {
        RedisTemplate redisTemplate = getRedisTemplate();
        Object value = redisTemplate.boundHashOps(getId()).get(key);
        log.info("[从缓存中获取了: " + key + "=" + value+" ]");
        return value;
    }

    @Override
    public Object removeObject(Object key) {
        RedisTemplate redisTemplate = getRedisTemplate();
        Object value = redisTemplate.boundHashOps(getId()).delete(key);
        log.info("[从缓存删除了: " + key + "=" + value+" ]");
        return value;
    }

    @Override
    public void clear() {
        RedisTemplate redisTemplate = getRedisTemplate();
        redisTemplate.delete(getId());
        log.info("清空缓存!!!");
    }

    @Override
    public int getSize() {
        RedisTemplate redisTemplate = getRedisTemplate();
        Long size = redisTemplate.boundHashOps(getId()).size();
        return size == null ? 0 : size.intValue();
    }

    @Override
    public ReadWriteLock getReadWriteLock() {
        return readWriteLock;
    }

}

因为RedisCache并不是Spring容器里的bean。 不能通过@Autowire的方式引用redisTemplate所以我们需要手动地去调用容器的getBean方法来拿到这个bean,那么这样,我们就需要引入ApplicationContextHolder这个类

@Component
public class ApplicationContextHolder implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    /**
     * 实现ApplicationContextAware接口的context注入函数, 将其存入静态变量.
     */
    public void setApplicationContext(ApplicationContext applicationContext) {
        ApplicationContextHolder.applicationContext = applicationContext; // NOSONAR
    }

    /**
     * 取得存储在静态变量中的ApplicationContext.
     */
    public static ApplicationContext getApplicationContext() {
        checkApplicationContext();
        return applicationContext;
    }

    /**
     * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
     */
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) {
        checkApplicationContext();
        return (T) applicationContext.getBean(name);
    }

    /**
     * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
     */
    @SuppressWarnings("unchecked")
    public static <T> T getBean(Class<T> clazz) {
        checkApplicationContext();
        return (T) applicationContext.getBeansOfType(clazz);
    }

    /**
     * 清除applicationContext静态变量.
     */
    public static void cleanApplicationContext() {
        applicationContext = null;
    }

    private static void checkApplicationContext() {
        if (applicationContext == null) {
            throw new IllegalStateException("applicaitonContext未注入,请在applicationContext.xml中定义SpringContextHolder");
        }
    }

}

.xml : "MybatisRedisCache"为实现了MyBatis二级缓存cache接口的实现类路径

<cache type="com.mybatis.mybatisdemo.config.MybatisRedisCache">
</cache>

注意:在使用Resid做MyBatis缓存时,查询数据需要关联表时设置useCache=“false”,设置该语句不进行缓存,避免关联的表数据修改后,执行该语句查询的数据不正确。

<select id="selectByPrimaryKey" parameterType="java.lang.Integer" useCache="false" resultMap="BaseResultMap">