parameterType

传入多个参数

确切点是方法的输入参数,一般都是采用直接使用pojo类。此时在mapper.xml文件中的SQL语句不用再写parameterType属性,而是用arg0,arg1,arg2,arg3…或者param1,param2,param3…代替。

引出问题

    /*** 登录* @param name* @param passworld*/public User login(String name ,String password);
<!--登录-->
<select id="login" resultType="User">select * from tb_user where user_name = #{username} and password = #{password}
</select>
@Test
public void testLogin(){User u = userMapper.login("jack","123");System.out.println(u);
}

如果传入两个参数或者更多的参数,会发现,多个参数是找不到了,错误如下:

解决方式1

在mapper.xml中使用 0,1这样的序号去,0表示第一个参数,1表示第二个参数。(从0开始数)

    <!--登录--><select id="login" resultType="User">select * from tb_user where user_name = #{arg0} and password = #{arg1}</select>

或者 用param1 param2 这个时就是从1开始

    <!--登录--><select id="login" resultType="User">select * from tb_user where user_name = #{param1} and password = #{param2}</select>

解决方式2

通过@Param来指定参数名,你写什么就接受什么

#与$区别

1、$字符串拼接,#参数站位相当于?
2、$不能够防止sql注入,#可以防止sql注入的
3、$要考虑参类型 ,#不用考虑参数类型
4、$可以替换sql语句任何一个内容,#只能替换参数

#的用法

######不用考虑参数类型

######可以防止sql注入

<!--登录-->
<select id="login" resultType="User"><!--使用#-->select * from tb_user where user_name = #{name} and passworld = #{password}
</select>
/*** 登录*/
public User login(@Param("name") String name ,@Param("passworld") String passworld);
    @Testpublic void testLogin(){User u = userMapper.login("jack", "123");//#不用考虑参数类型User u = userMapper.login("' or '1' = '1", "' or '1' = '1");//#防止sql注入System.out.println(u);}
  • 根据姓名进行模糊查询
    /*** 根据姓名进行模糊查询* @param name* @return*/public List<User> queryByLikeName(String name);
    <!--根据姓名进行模糊查询--><select id="queryByLikeName" resultType="User">select * from tb_user where user_name like concat('%',#{name},'%')</select>
    @Testpublic void teseQueryByLikeName(){List<User> list = this.userMapper.queryByLikeName("ja");for(User user : list){System.out.println(user);}}

$的用法

用于字符串拼接

    /*** 根据表名来查询* @param name*/public List<User> queryByTableName(String name);
    <!--根据表名来查询--><select id="queryByTableName" resultType="User">select * from ${name}</select>
    @Testpublic void testqueryByTableName(){List<User> list = this.userMapper.queryByTableName("tb_user");for(User user : list){System.out.println(user);}}

$ 需要考虑参数类型

$不防止sql注入

    <!--登录--><select id="login" resultType="User"><!--使用$ 需要考虑参数类型-->select * from tb_user where user_name = '${name}' and passworld = '${passworld}'</select>
/*** 登录*/
public User login(@Param("name") String name ,@Param("passworld") String passworld);
    @Testpublic void testLogin(){User u = userMapper.login("jack", "123");//$不用考虑参数类型User u = userMapper.login("' or '1' = '1", "' or '1' = '1");//$防止sql注入System.out.println(u);}

#和$的区别

$可以代替所有#
如果传入的数据,不是sql中的字段的时候,就不能够使用#. 通常使用#。
选择获取参数的时候,首要选择的# 的方式
(1、可以防止sql注入,2、可以不用考虑数据类型,简化书写,3、sql是参数的话的sql,预编译的sql,速度会块一些)
当#用不了的时候,去选择$例如 ,sql需要改变是表名的情况,就可使用$的方式。总结:能用# 就不选择$

ResultMap 用法

ResultMap 是Mybatis中最为重要的元素,使用ResultMap 可以解决两大问题:

1、pojo属性名与数据库字段名不一致问题

2、完成高级查询,一对一,一对多, 多对多(后面讲)

代码实现

    <!--查询所有映射--><!--id:resultMap的标识type:映射的类型autoMapping:true(默认) 支持 属性名与字段名自动映射  false:只针对resultMap定义的属性映射--><resultMap id="userResultMap" type="User" autoMapping="true">        <!--id一般作为主键,它有自己的标签,实现属性名与字段名一一映射--><id column="id" property="id"/>        <!--除了id以外的字段,用result标签实现属性名与字段名一一映射--><result column="user_name" property="userName"/>        <!--如果,属性名与字段一致,可以省略不写--><result column="sex" property="sex"/></resultMap><!--查询所有--><select id="queryAllUser" resultMap="userResultMap">select * from tb_user</select>

sql片段

作用:把重复的sql语句抽出来来放到sql标签中,然后通来引入

用法1

    <!--抽取sql--><sql id="userColumn">id ,user_name ,passworld , sex</sql><!--查询所有--><select id="queryAllUser" resultMap="userResultMap">select <include refid="userColumn"/> from tb_user</select>

如出现以下问题,请参考解决即可:

去掉xml:iBatis3:sql|select|insert|update|delete|statement里面的sql校验即可

用法2

以下用法1抽取的sql只能在本xml中使用,那如何这个抽取的sql其他xml也想使用怎么办呢?用法2就是可以将sql单独抽取到一个文件中,这样其他的xml就可以直接使用

<mapper namespace="abc"><!--抽取sql--><sql id="userColumn">id ,user_name ,passworld , sex</sql>
</mapper>
    <!--查询所有--><select id="queryAllUser" resultMap="userResultMap">select <include refid="abc.userColumn"/> from tb_user</select>
<!--注意别忘了:mybatis-config.xml 引入-->
<mapper resource="UserSQLMapper.xml"/>

动态sql

业务场景:在我们生活中很多业务常常遇到动态搜索的情况,比如搜索民宿,根据位置,价格,面积等等情况动态搜索,参数等信息可以根据我们需求改变,这里就涉及到了我们Mybatis常说的动态SQL。

Mybatis 动态SQL,通过 if, choose, when, otherwise, trim, where, set, foreach等标签,可组合成非常灵活的SQL语句,从而在提高 SQL 语句的准确性的同时,也大大提高了开发人员的效率。

Mybatis提供了动态SQL,也就是可以根据用户提供的参数,动态决定查询语句依赖的查询条件或SQL语句的内容。

标签名 解释
if 单条件分支判断
choose, when, otherwise 多条件分支判断
where 处理sql条件接拼where
set 处理sql条件接拼set
foreach 循环操作
trim 处理sql条件拼接

动态sql-if标签

需求1:查询男性用户,如果输入了姓名,姓名进行模糊查找,如果不输入就按男性用户来查询

    /**查询男性用户,如果输入了姓名,姓名进行模糊查找,如果不输入就按男性用户来查询*/public List<User> queryLikeByName(String name);
    <!--查询男性用户,如果输入了姓名,姓名进行模糊查找,如果不输入就按男性用户来查询--><select id="queryLikeByName" resultType="User">select * from tb_user where sex = '男'<if test="name != null and name !=''">and user_name like concat('%',#{name},'%')</if></select>
    //查询男性用户,如果输入了姓名,姓名进行模糊查找,如果不输入就按男性用户来查询@Testpublic void queryLikeByName() {List<User> list = this.userMapper.queryLikeByName("ck");for(User user : list){System.out.println(user);}}

动态sql-choose, when, otherwise标签

choose,when,otherwise 相当于java中的 if, else if的逻辑

如果其中的一个when 成立,则后的都不执行,如果所有when的都不成立,那么就执行otherwise

也就是谁在前面谁优先

需求2:查询男性用户,如果输入了姓名则按照姓名模糊查找,否则如果输入了年龄则按照年龄查找

    /*** 查询男性用户,如果输入了姓名则按照姓名模糊查找,否则如果输入了年龄则按照年龄查找*/public List<User> queryByLikeNameAndAge(@Param("name") String name , @Param("age") Integer age);
    <!--查询男性用户,如果输入了姓名则按照姓名模糊查找,否则如果输入了年龄则按照年龄查找--><select id="queryByLikeNameAndAge" resultType="User">select * from tb_user where sex = '男'<choose><when test="name != null and name !=''">and user_name like concat('%',#{name},'%')</when><when test="age != null and age !=''">and age like concat('%',#{age},'%')</when><otherwise>and id = 12</otherwise></choose></select>
 //查询男性用户,如果输入了姓名则按照姓名模糊查找,否则如果输入了年龄则按照年龄查找@Testpublic void queryByLikeNameAndAge(){List<User> list = this.userMapper.queryByLikeNameAndAge("jack", null);for(User user : list){System.out.println(user);}}

动态sql-where标签

where标签代替 sql中的where关键字

需求3:查询所有用户,如果输入了姓名按照姓名进行模糊查询,如果输入年龄,按照年龄进行查询

/**
* 查询所有用户,如果输入了姓名按照姓名进行模糊查询,如果输入年龄,按照年龄进行查询
*/
public List<User> queryByAllUserLikeNameAndAge(@Param("name") String name , @Param("age") Integer age);
    <!--查询所有用户,如果输入了姓名按照姓名进行模糊查询,如果输入年龄,按照年龄进行查询--><select id="queryByAllUserLikeNameAndAge" resultType="User">select * from tb_user<where><if test="name != null and name!=''">user_name like concat('%',#{name},'%')</if><if test="age != null and age!=''">and age like concat('%',#{age},'%')</if></where></select>
    //查询所有用户,如果输入了姓名按照姓名进行模糊查询,如果输入年龄,按照年龄进行查询@Testpublic void queryByAllUserLikeNameAndAge(){List<User> list = this.userMapper.queryByAllUserLikeNameAndAge("c", 2);for(User user : list){System.out.println(user);}}

动态sql-set标签

set标签代替 sql中set关键字

需求4:如果名字信息不是null,则修改名字, 如果age信息不是null,同时也修改age

/**
* 如果名字信息不是null,则修改名字, 如果age信息不是null,同时也修改age
*/
public Integer updateByNameOrAge(@Param("name") String name , @Param("age") Integer age , @Param("id") Integer id);
    <!--如果名字信息不是null,则修改名字, 如果age信息不是null,同时也修改age--><update id="updateByNameOrAge">update tb_user<set><if test="name != null and name!=''">user_name =  #{name},</if><if test="age != null and age!=''">age = #{age}</if></set>where id = #{id}</update>
    //如果名字信息不是null,则修改名字, 如果age信息不是null,同时也修改age@Testpublic void updateByNameOrAge(){Integer integer = this.userMapper.updateByNameOrAge("一燕", 26, 2);sqlSession.commit();System.out.println(integer);}

动态sql-foreach标签

需求5:按照多个id查询用户信息 Select * from t_user where id in(1,2,3)

    /*** 按照多个id查询用户信息* @param ids* @return*/public List<User> queryIds(@Param("ids") int[] ids);
    <!--按照多个id查询用户信息--><!--collection:接受的是一个集合item: 表示遍历的就量open: 字符串拼接的开头close: 字符串拼接的结尾separator: 每一个变量拼接的分隔符--><select id="queryIds" resultType="User">        select * from tb_user where id in<foreach collection="ids" item="id" open="(" close=")" separator=",">#{id}</foreach></select>
    // 按照多个id查询用户信息@Testpublic void queryIds(){int[] arr ={1,2};List<User> list = this.userMapper.queryIds(arr);for(User user : list){System.out.println(user);}}

动态sql-trim标签

trim元素的主要功能是可以在自己包含的内容前加上某些前缀,也可以在其后加上某写后缀,与之对应的属性是prefix和suffix;

可以把包含内容的首部某些内容覆盖,即忽略,也可以把尾部的某些内容覆盖,对应的属性是prefixOverrides和suffixOver

  • 案例一 prefix用法
/*** 查询所有,如果输入姓名,按姓名查询,如果输入性别,就按性别来查询*/
public List<User> queryNameAndSexTrim(@Param("name") String name , @Param("sex") String sex);
    <!--查询所有,如果输入姓名,按姓名查询,如果输入性别,就按性别来查询--><select id="queryNameAndSexTrim" resultType="User">select * from tb_user/*加前缀,去掉第一个前缀*/<trim prefix="where" prefixOverrides="and"><if test="name != null and name !=''">and user_name = #{name}</if><if test="sex != null and sex !=''">and sex = #{sex}</if></trim></select>
    //查询所有,如果输入姓名,按姓名查询,如果输入性别,就按性别来查询@Testpublic void queryNameAndSexTrim(){List<User> list = this.userMapper.queryNameAndSexTrim("jack", "男");for(User user : list){System.out.println(user);}}
  • **案例二 ** suffix用法

/**
* 如果名字信息不是null,则修改名字, 如果sex不为null,同时也修改null
*/
public Integer updateByNameOrAgeTrim(@Param("name") String name , @Param("sex") String sex , @Param("id") Integer id);
   <!--如果名字信息不是null,则修改名字, 如果sex不为null,同时也修改null--><update id="updateByNameOrAgeTrim">update tb_user<trim prefix="set" suffixOverrides="," suffix="where id = #{id}"><if test="name != null and name !=''">user_name = #{name},</if><if test="sex != null and sex !=''">sex = #{sex},</if></trim></update>
//如果名字信息不是null,则修改名字, 如果sex不为null,同时也修改null
@Test
public void updateByNameOrAgeTrim(){Integer integer = this.userMapper.updateByNameOrAgeTrim("小江", "女", 2);sqlSession.commit();System.out.println(integer);}

缓存

一级缓存

Mybatis的一级缓存的作用域session,当openSession()后,如果执行相同的sql和参数,Mybatis不再执行SQL,而是从缓存中命中并返回;

原理:mybatis执行查询时首先去缓存中命中,如果命中就直接返回,没有命中则执行SQL,从数据库中查

在mybatis中,一级缓存默认是开启的,并且一直无法关闭(我们没法去管理一级缓存

测试一级缓存

    @Testpublic void queryById(){User user = this.userMapper.queryById(2);//发送sqlSystem.out.println(user);User user2 = this.userMapper.queryById(2);//不发送sqlSystem.out.println(user2);}

清空缓存

使用sqlsession.clearCache()清除缓存

    @Testpublic void queryById(){User user = this.userMapper.queryById(2);//发送sqlSystem.out.println(user);sqlSession.clearCache();//清空缓存User user2 = this.userMapper.queryById(2);//重新发送sqlSystem.out.println(user2);}

执行update,delete,insert 语句的时候,清空缓存 刷新缓存

    @Testpublic void queryById(){User user = this.userMapper.queryById(2);//发送sqlSystem.out.println(user);Integer i = this.userMapper.deleteById(1);//执行删除操作sqlSession.commit();System.out.println(i);//只要执行任意的增删改,则会清空缓存;User user2 = this.userMapper.queryById(2);//发送sqlSystem.out.println(user2);}

二级缓存

mybatis 的二级缓存的作用域是一个mapper的namespace ,同一个namespace中查询sql可以从缓存中命中。

二级缓存是跨session

开启二级缓存

需要在当前sql映射文件中开启二缓缓存

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.yanqi.mapper.UserMapper">    <!--开启二级缓存--><cache/>

测试二级缓存

@Test
public void queryById(){User user = this.userMapper.queryById(2);//发送sqlSystem.out.println(user);//关闭sqlSessionsqlSession.close(); SqlSession sqlSession = sqlSessionFactory.openSession();userMapper = sqlSession.getMapper(UserMapper.class);User user2 = this.userMapper.queryById(2);//不发送sql,表明二级缓存存在System.out.println(user2);
}

查看日志输出

关闭二级缓存

<settings><!--开启驼峰匹配--><setting name="mapUnderscoreToCamelCase" value="true"/><!--关闭二级缓存  默认是开启的--><setting name="cacheEnabled" value="false"/></settings>

Mybatis一级缓存
1.为什么需要Mybatis一级缓存
当我们使用Mybatis进行数据库的操作时候,会创建一个SqlSession来进行一次数据库的会话,会话结束则关闭SqlSession对象。

如果我们很有可能多次查询完全相同的sql语句,每一次查询都查询一次数据库,那查询数据库代价是比较大的,这会导致系统的资源浪费。

为了解决这个问题,Mybatis对每一次会话都添加了缓存操作,不用相同的SQL每次都需要查询数据库,这就是Mybatis一级缓存的作用。

2.Mybatis一级缓存的实现
我们知道对SqlSession的操作,mybatis内部都是通过Executor来执行的,Executor的生命周期和SqlSession是一致的。

Mybatis在Executor中创建了本地缓存(一级缓存),如下图所示:

大致的流程如下:

第一次查询用户id信息,先去缓存中查询是否有,如果没有,从数据库中查询用户信息,得到用户信息后在将用户信息储存到一级缓存中。

如果sqlSession去执行commit操作(插入、更新、删除),清空sqlSession中的一级缓存,保证缓存中始终保存的是最新的信息,避免脏读。

第二次查询用户id信息,先去缓存中查询,如缓存中有,直接从缓存中获取。

注意:两次查询须在同一个sqlsession中完成,否则将不会走mybatis的一级缓存。

在mybatis与spring进行整合开发时,事务控制在service中进行,重复调用两次servcie将不会走一级缓存,因为在第二次调用时session方法结束,SqlSession就关闭了。

3.Mybatis一级缓存配置
mybatis一级缓存的范围有SESSION和STATEMENT两种,默认是SESSION。

如果不想使用一级缓存,可以把一级缓存的范围指定为STATEMENT,这样每次执行完一个Mapper中的语句后都会将一级缓存清除。

如果需要更改一级缓存的范围,可以在Mybatis的配置文件中,在下通过localCacheScope指定。

Mybatis二级缓存 1.为什么需要Mybatis二级缓存? MyBatis 一级缓存最大的共享范围就是一个SqlSession内部,那么如果多个 SqlSession 需要共享缓存,则需要开启二级缓存。

2.Mybatis二级缓存的实现
开启二级缓存后,会使用 CachingExecutor 装饰 Executor,进入一级缓存的查询流程前,先在 CachingExecutor 进行二级缓存的查询,具体的工作流程如下所示。

二级缓存开启后,同一个 namespace 下的所有操作语句,都影响着同一个 Cache,即二级缓存被多个 SqlSession 共享,是一个全局的变量。

当开启缓存后,数据的查询执行的流程就是 二级缓存 -> 一级缓存 -> 数据库。

MyBatis 是默认关闭二级缓存的,因为对于增删改操作频繁的话,那么二级缓存形同虚设,每次都会被清空缓存。

Mybatis一级缓存与二级缓存的区别
1)一级缓存 Mybatis的一级缓存是指SQLSession,一级缓存的作用域是SQlSession, Myabits默认开启一级缓存。

在同一个SqlSession中,执行相同的SQL查询时;第一次会去查询数据库,并写在缓存中,第二次会直接从缓存中取。 当执行SQL时候两次查询中间发生了增删改的操作,则SQLSession的缓存会被清空。

每次查询会先去缓存中找,如果找不到,再去数据库查询,然后把结果写到缓存中。 Mybatis的内部缓存使用一个HashMap,key为hashcode+statementId+sql语句。Value为查询出来的结果集映射成的java对象。 SqlSession执行insert、update、delete等操作commit后会清空该SQLSession缓存。

2) Mybatis二级缓存是默认不开启的,作用于一个Application,是Mapper级别的,多个SqlSession使用同一个Mapper的sql能够使用二级缓存。
xecutor 装饰 Executor,进入一级缓存的查询流程前,先在 CachingExecutor 进行二级缓存的查询,具体的工作流程如下所示。

[外链图片转存中…(img-TITjBxut-1665230984236)]

二级缓存开启后,同一个 namespace 下的所有操作语句,都影响着同一个 Cache,即二级缓存被多个 SqlSession 共享,是一个全局的变量。

当开启缓存后,数据的查询执行的流程就是 二级缓存 -> 一级缓存 -> 数据库。

MyBatis 是默认关闭二级缓存的,因为对于增删改操作频繁的话,那么二级缓存形同虚设,每次都会被清空缓存。

Mybatis一级缓存与二级缓存的区别
1)一级缓存 Mybatis的一级缓存是指SQLSession,一级缓存的作用域是SQlSession, Myabits默认开启一级缓存。

在同一个SqlSession中,执行相同的SQL查询时;第一次会去查询数据库,并写在缓存中,第二次会直接从缓存中取。 当执行SQL时候两次查询中间发生了增删改的操作,则SQLSession的缓存会被清空。

每次查询会先去缓存中找,如果找不到,再去数据库查询,然后把结果写到缓存中。 Mybatis的内部缓存使用一个HashMap,key为hashcode+statementId+sql语句。Value为查询出来的结果集映射成的java对象。 SqlSession执行insert、update、delete等操作commit后会清空该SQLSession缓存。

2) Mybatis二级缓存是默认不开启的,作用于一个Application,是Mapper级别的,多个SqlSession使用同一个Mapper的sql能够使用二级缓存。

JAVAEE框架技术之8-myBatis ORM框架技术参数和动态SQL语句相关推荐

  1. mybatis中mapper文件中的动态sql语句

    有时候在检索时,用户提供的数据不一样多,我们很难使用静态的sql语句进行判别,所以这个时候需要使用动态的sql语句 这里主要针对Mapper.xml文件中的sql语句,笔者在下面所有的例子中只提供了M ...

  2. 手写MyBatis ORM框架

    手写MyBatis ORM框架 目标: 实现: 思路: 一.前期准备 1.加入依赖 2.自定义插入注解 3.自定义删除注解 4.自定义更新注解 5.自定义查询注解 6.自定义参数注解 7.定义和数据库 ...

  3. mybatis —— ORM框架

    一.什么是框架         框架是一种经过校验.具有一定功能的半成品软件品,已经对基础的代码进行了封装并提供相应的API,开发者在使用框架是直接调用封装好的api可以省去很多代码编写,从而提高工作 ...

  4. ORM框架如何选型——各大ORM框架比较

                                             ORM框架如何选型--各大ORM框架比较 现有ORM框架或ORM相关框架主要有Hibernate,Mybatis.这两 ...

  5. Bee框架(速学)ORM框架(速学教程)

    Bee框架(速学)ORM框架(速学教程) Bee 是一个ORM框架.关注:省时/优雅.简易.自动( Tea: Timesaving/Tasteful, Easy, Automatic) 特性.减少开发 ...

  6. Mybatis Plus 是如何实现动态 SQL 语句的?原理你懂吗?

    作者 | 稻草江南 来源 | https://juejin.cn/post/6883081187103866894 Mybatis-Plus(简称MP)是一个 Mybatis 的增强工具,那么它是怎么 ...

  7. Mybatis 动态Sql语句《常用》

    MyBatis 的强大特性之一便是它的动态 SQL.如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么痛苦.拼接的时候要确保不能忘了必要的空格,还要注意省掉 ...

  8. 【转】mybatis实战教程(mybatis in action)之八:mybatis 动态sql语句

    转自:除非申明,文章均为一号门原创,转载请注明本文地址,谢谢! 转载地址:http://blog.csdn.net/kutejava/article/details/9164353#t5 1. if ...

  9. Mybatis—动态SQL语句与逆向工程

    Mybatis动态SQL语句与逆向工程 MyBatis动态SQL语句与逆向工程 1.动态SQL语句 1.1.动态SQL是什么 1.2.动态SQL有什么用 1.3.基于XML的实现 1.3.2.接口文件 ...

最新文章

  1. 《ActionScript 3.0基础教程》——第2章 往舞台动态地添加对象2.1 创建库资源,并为它命名...
  2. 技术干货 | 高性能短链设计与实现
  3. python地图 两点距离_没学过还真不会!怎样才能画出准确的地图?
  4. dj鲜生-09-商品应用-首页的显示
  5. Eclipse中Program arguments和VM arguments的说明
  6. Ant Design Pro v4 is Here
  7. OpenShift 4 之Service Mesh教程(5)- 断路器Circuit Breaker
  8. BZOJ1354: [Baltic2005]Bus Trip
  9. MySQL下xtrabackup与MTS造成的死锁
  10. Spring时间(Date)类型转换+自定义
  11. python调用讯飞付费版语音转写
  12. Turtlebot2激光雷达(Rplidar)gmapping构建地图
  13. 生活中的一些哲理名言
  14. javascript数字转汉字中文数字
  15. 菜刀、冰蝎、蚁剑、哥斯拉
  16. AlexNet网络介绍
  17. 怎样快速抠图ps图片?这些小妙招了解一下
  18. HTML自动点名代码,js+html实现点名系统功能
  19. android相机故障代码解决方法,Android相机服务器死机和相机错误 – 100
  20. Springboot 集成 mybatis 开启二级缓存(redis)

热门文章

  1. java射雕英雄传完美结局_关于83版射雕英雄传
  2. css3设置动画不循环播放,不一样的css3之Animation
  3. javascript正则表达式截取字符串
  4. winserver使用照片查看器查看图片的设置方法
  5. 云媒易:如何打造抖音推广人设,加深用户记忆点?
  6. 【深入理解】Python网络编程
  7. win10盗贼之海闪退的问题怎么办?
  8. 倒计时一天!Pulsar Summit Asia 2020 演讲征集即将结束
  9. 极客日报第3期:小红书回应 “涉黄内容” 已封禁;iOS 14.2 推送,你更新了吗?
  10. Python学习备忘笔记——Python概述