1.1【bug】在false后面加了空格,我的源代码中在false后面换行了
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】
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 模糊查询(两种方法)
string wildcardname = “%smi%”;list<name> names = mapper.selectlike(wildcardname);<select id=”selectlike”>select * from foo where bar like #{value}</select>
string wildcardname = “smi”;list<name> names = mapper.selectlike(wildcardname);<select id=”selectlike”>select * from foo where bar like "%"#{value}"%"</select>
1.5一些优化(一定要注意标签的顺序,标签需要按顺序排列)
Properties优化:
第一步 ; 在资源目录下新建一个db.properties第二步 : 将文件导入properties 配置文件
typeAliases优化
<!--配置别名,注意顺序--><typeAliases><typeAlias type="com.yuanziwei.www.pojo.User" alias="user"/></typeAliases>
<!--每一个在包 com.kuang.pojo 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。--><typeAliases><package name="com.yuanziwei.www.pojo"/></typeAliases>
适配器
MapperRegistry注册绑定mapper文件的注意点
接口和他的Mapper配置文件必须同名
接口和他的Mapper配置文件必须在同一包下
配置文件UserMapper.xml对应-->接口:UserMapper
1.6作用域(Scope)和生命周期
SqlSessionFactoryBuilder:
局部变量
一旦创建了SqlSessionFactory,就不再需要它了
SqlSessionfactory:
可以想象为:数据库连接池
SqlSessionFactory一旦创建应该在运行期间一直存在,因此最佳作用域是应用作用域
使用单例模式
SqlSession
连接到连接池的一个请求
SqlSession的实例不是线程安全的,因此是不能被共享的,所以它的最佳作用域是请求或方法的作用域
用完之后需要赶紧关闭,否则资源被占用
1.7ResultMap
<resultMap id="UserMap" type="User"><!-- id为主键 --><id column="id" property="id"/><!-- column是数据库表的列名 , property是对应实体类的属性名 --><result column="name" property="name"/><result column="pwd" property="password"/></resultMap><select id="selectUserById" resultMap="UserMap">select id , name , pwd from user where id = #{id}</select>
1.8mybatis缓存机制
MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存
- 默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)
- 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
- 为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存
一级缓存失效的四种情况
1.sqlSession不同
@Testpublic void testQueryUserById(){SqlSession session = MybatisUtils.getSession();SqlSession session2 = MybatisUtils.getSession();UserMapper mapper = session.getMapper(UserMapper.class);UserMapper mapper2 = session2.getMapper(UserMapper.class);User user = mapper.queryUserById(1);System.out.println(user);User user2 = mapper2.queryUserById(1);System.out.println(user2);System.out.println(user==user2);session.close();session2.close();}
2.sqlSession相同,查询条件不同
@Testpublic void testQueryUserById(){SqlSession session = MybatisUtils.getSession();UserMapper mapper = session.getMapper(UserMapper.class);UserMapper mapper2 = session.getMapper(UserMapper.class);User user = mapper.queryUserById(1);System.out.println(user);User user2 = mapper2.queryUserById(2);System.out.println(user2);System.out.println(user==user2);session.close();}
3.sqlSession相同,两次查询之间执行了增删改操作!
@Testpublic void testQueryUserById(){SqlSession session = MybatisUtils.getSession();UserMapper mapper = session.getMapper(UserMapper.class);User user = mapper.queryUserById(1);System.out.println(user);HashMap map = new HashMap();map.put("name","kuangshen");map.put("id",4);mapper.updateUser(map);User user2 = mapper.queryUserById(1);System.out.println(user2);System.out.println(user==user2);session.close();}
4.sqlSession相同,手动清除一级缓存
@Testpublic void testQueryUserById(){SqlSession session = MybatisUtils.getSession();UserMapper mapper = session.getMapper(UserMapper.class);User user = mapper.queryUserById(1);System.out.println(user);session.clearCache();//手动清除缓存User user2 = mapper.queryUserById(1);System.out.println(user2);System.out.println(user==user2);session.close();}
1.9动态SQL
SQL片段:
某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们可以将这些代码抽取出来,然后使用时直接调用
提取sql片段:
<sql id="if-title-author"><if test="title != null">title = #{title}</if><if test="author != null">and author = #{author}</if></sql>
引用sql片段:
<select id="queryBlogIf" parameterType="map" resultType="blog">select * from blog<where><!-- 引用 sql 片段,如果refid 指定的不在本文件中,那么需要在前面加上 namespace --><include refid="if-title-author"></include><!-- 在这里还可以引用其他的 sql 片段 --></where></select>
mybatis核心配置文件,下划线驼峰自动转换
<setting name="mapUnderscoreToCamelCase" value="true"/>
choose标签
<!-- choose 和 when , otherwise 是配套标签类似于java中的switch,只会选中满足条件的一个--><select id="findActiveBlogLike"resultType="Blog">SELECT * FROM BLOG WHERE state = ‘ACTIVE’<choose><when test="title != null">AND title like #{title}</when><when test="author != null and author.name != null">AND author_name like #{author.name}</when><otherwise>AND featured = 1</otherwise></choose></select>
if标签
<select id="queryBlogIf" parameterType="map" resultType="blog">select * from blog where<if test="title != null">title = #{title}</if><if test="author != null">and author = #{author}</if></select>
where标签
<select id="queryBlogIf" parameterType="map" resultType="blog">select * from blog<where><if test="title != null">title = #{title}</if><if test="author != null">and author = #{author}</if></where></select>
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>
foreach
<select id="queryBlogForeach" parameterType="map" resultType="blog">select * from blog<where><!--collection:指定输入对象中的集合属性item:每次遍历生成的对象open:开始遍历时的拼接字符串close:结束时拼接的字符串separator:遍历对象之间需要拼接的字符串select * from blog where 1=1 and (id=1 or id=2 or id=3)--><foreach collection="ids" item="id" open="and (" close=")" separator="or">id=#{id}</foreach></where></select>
2.0MyBatis批量插入几千条数据慎用foreach
<insert id="batchInsert" parameterType="java.util.List">insert into USER (id, name) values<foreach collection="list" item="model" index="index" separator=",">(#{model.id}, #{model.name})</foreach></insert>
这个方法提升批量插入速度的原理是,将传统的:
INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");
转化为:
INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2"),("data1", "data2"),("data1", "data2"),("data1", "data2"),("data1", "data2");
乍看上去这个foreach没有问题,但是经过项目实践发现,当表的列数较多(20+),以及一次性插入的行数较多(5000+)时,整个插入的耗时十分漫长,达到了14分钟,这是不能忍的。
耗时就耗在,由于我foreach后有5000+个values,所以这个PreparedStatement特别长,包含了很多占位符,对于占位符和参数的映射尤其耗时。并且,查阅相关资料可知,values的增长与所需的解析时间,是呈指数型增长的。
总结
总结一下,如果MyBatis需要进行批量插入,推荐使用 ExecutorType.BATCH 的插入方式,如果非要使用 的插入的话,需要将每次插入的记录控制在 20~50 左右。
