实践篇
1、#{}和${}的区别
${}
直接替换变量 (有sql注入风险),使用场景:当表名、字段名作为变量传入时。
#{}
(PreparedStatement) 预处理编译,先替换为? 然后赋值 添加单引号。
2、使用注解和xml文件sql的方式区别?
注解:简单明了,无需额外文件。但长sql格式不友好,且无法额外做if等逻辑处理。
sql:能弥补注解sql的缺点,但对于不同场景下共用sql的情况,要处理好参数是否必须传入的问题。
3、使用map接收结果集时,有时会遇到属性的类型与预想的不一致。
在使用Map接收时,“type”的数据类型并非Integer,而是Long。这里涉及到JavaType和JDBCType之间的对应关系,在给参数赋值和结果集两个地方都会遇到。
尽量不要用map(好存不好取,不透明),改用dto等对象实体。明确每个字段的类型。
select case a.type when 1 then 2 when 2 then 3 else 0 end as type from table
4、使用druid时,默认批量插入失效?
druid为了安全考虑,默认不开启批量操作。需要手动配置,以下是在Springboot中的配置。
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
DruidDataSource datasource = new DruidDataSource();
List<Filter> filters = new ArrayList<>();
filters.add(wallFilter());
datasource.setProxyFilters(filters);
return datasource;
}
@Bean
public WallFilter wallFilter(){
WallFilter wallFilter = new WallFilter();
//允许执行多条SQL
WallConfig config = new WallConfig();
config.setMultiStatementAllow(true);
wallFilter.setConfig(config);
return wallFilter;
}
5、使用ResultMap接收结果集时,需要注意的问题
当遇到map中新增或删除属性或数据类型变更等问题时,要考虑其他使用该map的方法。
<resultMap id="BaseResultMap" type="com.aoji.model.TaskTemplateInfo">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="code" jdbcType="VARCHAR" property="code" />
<result column="message" jdbcType="VARCHAR" property="message" />
</resultMap>
6、批量插入sql时,foreach两种方式的比较
第一种:✅
insert into table (user_id,create_time, delete_status ) VALUES
<foreach collection="add" item="item" separator=",">
(#{item.userId},#{item.createTime}, #{item.deleteStatus})
</foreach>
第二种:❌ (本质是多条insert,并非一条sql的批量操作。)
<foreach collection="add" item="item" separator=",">
insert into table (user_id,create_time, delete_status ) VALUES (#{item.userId},#{item.createTime}, #{item.deleteStatus})
</foreach>
7、需要并发校验的场景,不要直接扔给数据库。
服务层面需处理并发同步问题,若直接扔给数据库,会加剧数据库压力。也会产生很多报错信息。
<insert id="insertOrUpdateStudentMaterialManage" parameterType="list">
INSERT INTO table (
`id`,`business_id`,`material_name`,`business_type`,`material_url`,`only_read`,`material_describe`,`material_sort`,
`delete_status`,`operator_no`,`operator_name`
)VALUES
<foreach collection="list" item="material" separator=",">
(#{material.id},#{material.businessId}, #{material.materialName}, #{material.businessType}, #{material.materialUrl},
#{material.onlyRead},#{material.materialDescribe},#{material.materialSort},
#{material.deleteStatus}, #{material.operatorNo},#{material.operatorName})
</foreach>
on duplicate key update
material_name=values(material_name),business_type = values(business_type),material_url = values(material_url),
only_read = values(only_read),material_describe = values(material_describe),
material_sort = values(material_sort),delete_status=values(delete_status),
operator_no=values(operator_no),operator_name=values(operator_name)
</insert>
8、mapper中方法考虑是否复用时,一定要慎重!
一味的考虑sql语句的复用,会使得原本简单的sql变得十分复杂臃肿,难以维护。尽量参考单一原则,不能只看当前业务。
原理篇
1、为什么Mybatis不需要为Mapper接口提供实现类?
Mybatis通过动态代理,根据我们提供的xml文件或者CRUD注解,为mapper接口动态的生成实现类。
2、Mybatis的拦截器如何实现?
参见之前博客《【Review】Mybatis-以PageHelper为例分析拦截器》
未完待续…