1.1【bug】在false后面加了空格,我的源代码中在false后面换行了

  1. The connection property 'useSSL' only accepts values of the form: 'true', 'false', 'yes' or 'no'. The value 'false ' is not in this set.

1.2【bug】

  1. Client does not support authentication protocol requested by server; consider upgrading MySQL client

当时看到这个问题人麻了,因为要让我去升级navicat,这个东东本来就需要下载破解版,而且还需要重新下载,那就挺麻烦的

然后我去查了资料,发现这个问题通常是mysql客户端或者jdbc包版本不匹配(一个版本高一个版本低),你需要升高或者降低mysql客户端或者jdbc包的版本,因为改变jdbc包比较方便,mysql客户端需要重新安装,所以把jdbc版本从五点几改为八点几就ok了

1.3【注意】

在写url语句时,引号里面的&需要写成&

1.4 模糊查询(两种方法)

  1. string wildcardname = “%smi%”;
  2. list<name> names = mapper.selectlike(wildcardname);
  3. <select id=”selectlike”>
  4. select * from foo where bar like #{value}
  5. </select>
  1. string wildcardname = smi”;
  2. list<name> names = mapper.selectlike(wildcardname);
  3. <select id=”selectlike”>
  4. select * from foo where bar like "%"#{value}"%"
  5. </select>

1.5一些优化(一定要注意标签的顺序,标签需要按顺序排列)

Properties优化:

  1. 第一步 ; 在资源目录下新建一个db.properties
  2. 第二步 : 将文件导入properties 配置文件

typeAliases优化

  1. <!--配置别名,注意顺序-->
  2. <typeAliases>
  3. <typeAlias type="com.yuanziwei.www.pojo.User" alias="user"/>
  4. </typeAliases>
  1. <!--每一个在包 com.kuang.pojo 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。-->
  2. <typeAliases>
  3. <package name="com.yuanziwei.www.pojo"/>
  4. </typeAliases>

适配器

MapperRegistry注册绑定mapper文件的注意点

接口和他的Mapper配置文件必须同名

接口和他的Mapper配置文件必须在同一包下

  1. 配置文件UserMapper.xml对应-->接口:UserMapper

1.6作用域(Scope)和生命周期

SqlSessionFactoryBuilder:

局部变量
一旦创建了SqlSessionFactory,就不再需要它了

SqlSessionfactory:

可以想象为:数据库连接池

SqlSessionFactory一旦创建应该在运行期间一直存在,因此最佳作用域是应用作用域

使用单例模式

SqlSession

连接到连接池的一个请求

SqlSession的实例不是线程安全的,因此是不能被共享的,所以它的最佳作用域是请求或方法的作用域

用完之后需要赶紧关闭,否则资源被占用

1.7ResultMap

  1. <resultMap id="UserMap" type="User">
  2. <!-- id为主键 -->
  3. <id column="id" property="id"/>
  4. <!-- column是数据库表的列名 , property是对应实体类的属性名 -->
  5. <result column="name" property="name"/>
  6. <result column="pwd" property="password"/>
  7. </resultMap>
  8. <select id="selectUserById" resultMap="UserMap">
  9. select id , name , pwd from user where id = #{id}
  10. </select>

1.8mybatis缓存机制

MyBatis系统中默认定义了两级缓存:一级缓存二级缓存

  • 默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)
  • 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
  • 为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存

一级缓存失效的四种情况

1.sqlSession不同

  1. @Test
  2. public void testQueryUserById(){
  3. SqlSession session = MybatisUtils.getSession();
  4. SqlSession session2 = MybatisUtils.getSession();
  5. UserMapper mapper = session.getMapper(UserMapper.class);
  6. UserMapper mapper2 = session2.getMapper(UserMapper.class);
  7. User user = mapper.queryUserById(1);
  8. System.out.println(user);
  9. User user2 = mapper2.queryUserById(1);
  10. System.out.println(user2);
  11. System.out.println(user==user2);
  12. session.close();
  13. session2.close();
  14. }

2.sqlSession相同,查询条件不同

  1. @Test
  2. public void testQueryUserById(){
  3. SqlSession session = MybatisUtils.getSession();
  4. UserMapper mapper = session.getMapper(UserMapper.class);
  5. UserMapper mapper2 = session.getMapper(UserMapper.class);
  6. User user = mapper.queryUserById(1);
  7. System.out.println(user);
  8. User user2 = mapper2.queryUserById(2);
  9. System.out.println(user2);
  10. System.out.println(user==user2);
  11. session.close();
  12. }

3.sqlSession相同,两次查询之间执行了增删改操作!

  1. @Test
  2. public void testQueryUserById(){
  3. SqlSession session = MybatisUtils.getSession();
  4. UserMapper mapper = session.getMapper(UserMapper.class);
  5. User user = mapper.queryUserById(1);
  6. System.out.println(user);
  7. HashMap map = new HashMap();
  8. map.put("name","kuangshen");
  9. map.put("id",4);
  10. mapper.updateUser(map);
  11. User user2 = mapper.queryUserById(1);
  12. System.out.println(user2);
  13. System.out.println(user==user2);
  14. session.close();
  15. }

4.sqlSession相同,手动清除一级缓存

  1. @Test
  2. public void testQueryUserById(){
  3. SqlSession session = MybatisUtils.getSession();
  4. UserMapper mapper = session.getMapper(UserMapper.class);
  5. User user = mapper.queryUserById(1);
  6. System.out.println(user);
  7. session.clearCache();//手动清除缓存
  8. User user2 = mapper.queryUserById(1);
  9. System.out.println(user2);
  10. System.out.println(user==user2);
  11. session.close();
  12. }

1.9动态SQL

SQL片段:

某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们可以将这些代码抽取出来,然后使用时直接调用

提取sql片段:

  1. <sql id="if-title-author">
  2. <if test="title != null">
  3. title = #{title}
  4. </if>
  5. <if test="author != null">
  6. and author = #{author}
  7. </if>
  8. </sql>

引用sql片段:

  1. <select id="queryBlogIf" parameterType="map" resultType="blog">
  2. select * from blog
  3. <where>
  4. <!-- 引用 sql 片段,如果refid 指定的不在本文件中,那么需要在前面加上 namespace -->
  5. <include refid="if-title-author"></include>
  6. <!-- 在这里还可以引用其他的 sql 片段 -->
  7. </where>
  8. </select>

mybatis核心配置文件,下划线驼峰自动转换

  1. <setting name="mapUnderscoreToCamelCase" value="true"/>

choose标签

  1. <!-- choose 和 when , otherwise 是配套标签
  2. 类似于java中的switch,只会选中满足条件的一个
  3. -->
  4. <select id="findActiveBlogLike"
  5. resultType="Blog">
  6. SELECT * FROM BLOG WHERE state = ‘ACTIVE’
  7. <choose>
  8. <when test="title != null">
  9. AND title like #{title}
  10. </when>
  11. <when test="author != null and author.name != null">
  12. AND author_name like #{author.name}
  13. </when>
  14. <otherwise>
  15. AND featured = 1
  16. </otherwise>
  17. </choose>
  18. </select>

if标签

  1. <select id="queryBlogIf" parameterType="map" resultType="blog">
  2. select * from blog where
  3. <if test="title != null">
  4. title = #{title}
  5. </if>
  6. <if test="author != null">
  7. and author = #{author}
  8. </if>
  9. </select>

where标签

  1. <select id="queryBlogIf" parameterType="map" resultType="blog">
  2. select * from blog
  3. <where>
  4. <if test="title != null">
  5. title = #{title}
  6. </if>
  7. <if test="author != null">
  8. and author = #{author}
  9. </if>
  10. </where>
  11. </select>

set标签

  1. <!--注意set是用的逗号隔开-->
  2. <update id="updateBlog" parameterType="map">
  3. update blog
  4. <set>
  5. <if test="title != null">
  6. title = #{title},
  7. </if>
  8. <if test="author != null">
  9. author = #{author}
  10. </if>
  11. </set>
  12. where id = #{id};
  13. </update>

foreach

  1. <select id="queryBlogForeach" parameterType="map" resultType="blog">
  2. select * from blog
  3. <where>
  4. <!--
  5. collection:指定输入对象中的集合属性
  6. item:每次遍历生成的对象
  7. open:开始遍历时的拼接字符串
  8. close:结束时拼接的字符串
  9. separator:遍历对象之间需要拼接的字符串
  10. select * from blog where 1=1 and (id=1 or id=2 or id=3)
  11. -->
  12. <foreach collection="ids" item="id" open="and (" close=")" separator="or">
  13. id=#{id}
  14. </foreach>
  15. </where>
  16. </select>

2.0MyBatis批量插入几千条数据慎用foreach

  1. <insert id="batchInsert" parameterType="java.util.List">
  2. insert into USER (id, name) values
  3. <foreach collection="list" item="model" index="index" separator=",">
  4. (#{model.id}, #{model.name})
  5. </foreach>
  6. </insert>

这个方法提升批量插入速度的原理是,将传统的:

  1. INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");
  2. INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");
  3. INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");
  4. INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");
  5. INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");

转化为:

  1. INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2"),
  2. ("data1", "data2"),
  3. ("data1", "data2"),
  4. ("data1", "data2"),
  5. ("data1", "data2");

乍看上去这个foreach没有问题,但是经过项目实践发现,当表的列数较多(20+),以及一次性插入的行数较多(5000+)时,整个插入的耗时十分漫长,达到了14分钟,这是不能忍的。

耗时就耗在,由于我foreach后有5000+个values,所以这个PreparedStatement特别长,包含了很多占位符,对于占位符和参数的映射尤其耗时。并且,查阅相关资料可知,values的增长与所需的解析时间,是呈指数型增长的。

总结

总结一下,如果MyBatis需要进行批量插入,推荐使用 ExecutorType.BATCH 的插入方式,如果非要使用 的插入的话,需要将每次插入的记录控制在 20~50 左右。