目录
一、SSM思维导图
二、MyBatis是什么?
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 Bean 映射成数据库中的记录。
三、hibernate与mybatis使用心得
springboot时代之前,持久层最流行的就是hibernate和mybatis了,hibernate对数据库进行了重量级的封装,hibernate的思想和Java不谋而合,都是对象的思想。听起来很友好,但配合使用的hql就不那么友好了,hql可以说是sql的简化版本,hql是在sql上面套了一层,但是hql优化很难搞,hibernate使用了大量的反射机制,虽然hibernate的反射大多数都是在程序初始化的时候完成的,但运行的过程中反射也是存在的,反射比较影响程序性能。
mybatis是持久层的轻量级框架,定义一个接口mapper,一个xml,映射关系一匹配,再配置一个扫描包,目前也是持久层的主流写法。
还有第三种方式DruidDataSource + JdbcTemplate,实现了在Java中直接书写sql语句,同时还能进行简单的对象操作。结合了hibernate和mybatis的部分优点,完美的产物?不存在的,到处都是sql,为以后的代码重构,框架重整,带来了不必要的麻烦,而且总感觉DruidDataSource + JdbcTemplate有一种lowlow的感觉。
四、漫谈hibernate
1、hibernate优势
hibernate让你不用写sql了,这不单可以让你的应用更好移植其它数据库,更主要的是让程序员更专注业务逻辑、数据关系、对象关系等。hibernate对一对多,多对多关系实现是非常好的。很关键一点,它支持lazy,可以让你的数据只在需要的时候被加载,听起来很完美。hibernate还有一个更牛的就是HQL,这是完全可以把查询映射到你OO模型的查询语言,和mybatis的映射比起来,还是更方便和更强大的。
2、hibernate劣势
- 难以使用数据库的一些功能
- 满足不了程序对cache的需求
- 耦合度高
- debug难
- hibernate更新大批量数据难度高
- hibernate删除大批量数据难度高
五、mybatis特点
- 简单易学:本身就很小且简单,没有任何第三方依赖,引入jar包,配置xml即可。
- 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
- 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
- 提供映射标签,支持对象与数据库的orm字段关系映射。
- 提供对象关系映射标签,支持对象关系组建维护。
- 提供xml标签,支持编写动态sql。
六、mybatis中#和$的区别
1、#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。
如:where id=#{id},如果传入的值是1,那么解析成sql时的值为where id=“1”, 如果传入的值是id,则解析成的sql为where id=“id”。
2、将传入的数据直接显示生成在sql中。
如:where id=${id},如果传入的值是1,那么解析成sql时的值为where username=1;
如果传入的值是;drop table user;,则解析成的sql为:
select * from student where id=1;drop table student;
3、#方式能够很大程序防止sql注入,$方式无法防止sql注入。
4、$方式一般用于传入数据库对象,比如表明。
5、一般能用#的就不要使用,若不得不使用,则要做好前期校验工作,防止sql注入攻击。
6、在mybatis中,涉及到动态表名和列名时,只能使用${xxx}这样的参数形式。所以这样的参数需要我们在代码中手工进行处理来防止注入。
七、mybatis是如何防止sql注入的
MyBatis框架作为一款半自动化的持久层框架,其SQL语句都要我们自己手动编写,这个时候当然需要防止SQL注入。其实,MyBatis的SQL是一个具有“输入+输出”的功能,类似于函数的结构,参考上面的两个例子。其中,parameterType表示了输入的参数类型,resultType表示了输出的参数类型。回应上文,如果我们想防止SQL注入,理所当然地要在输入参数上下功夫。上面代码中使用#的即输入参数在SQL中拼接的部分,传入参数后,打印出执行的SQL语句,会看到SQL是这样的:
select * from student where id=? and name=?
不管输入什么参数,打印出的SQL都是这样的。这是因为MyBatis启用了预编译功能,在SQL执行前,会先将上面的SQL发送给数据库进行编译;执行时,直接使用编译好的SQL,替换占位符“?”就可以了。因为SQL注入只能对编译过程起作用,所以这样的方式就很好地避免了SQL注入的问题。
八、mybatis中的顶级标签
1、sql – 可被其他语句引用的可重用语句块
<sqlid="valid"> where valid = 1 </sql><selectid='queryUser'>select * from user <includerefid='valid'></include>
2、insert – 映射插入语句
<insertid="saveUser">insert into User (id,name,sex) values (#{id},#{name},#{sex})<insert>
3、update – 映射更新语句
<updateid="updateUser">
update User set
name = #{name},
sex= #{sex}
where id = #{id}
</update>
4、delete – 映射删除语句
<deleteid="deleteUser">
delete from User where id = #{id}
</delete>
九、动态sql标签
1、if
<selectid="findUserByName"resultType="User">
SELECT * FROM User
WHERE valid = 1
<iftest="name!= null">
AND name like #{name}
</if></select>
2、choose (when, otherwise)
<selectid="findUser"resultType="User">
SELECT * FROM User WHERE age = 26
<choose><whentest="name!= null">
AND name like #{name}
</when><whentest="sex!= null ">
AND sex like #{sex}
</when><otherwise>
AND valid = 1
</otherwise></choose></select>
3、trim (where, set)
<!-- prefixOverrides 属性会忽略通过管道分隔的文本序列
(注意此例中的空格也是必要的)。它的作用是移除所有指定
在prefixOverrides 属性中的内容,并且插入 prefix
属性中指定的内容。--><trimprefix="WHERE"prefixOverrides="AND |OR ">
...
</trim><!-- set 元素会动态前置
SET 关键字,同时也会删掉无关的逗号 --><trimprefix="SET"suffixOverrides=",">
...
</trim>
4、foreach
<!-- collection="要遍历的集合"
item = "可以在元素体内使用的集合项"
index = "索引"
open = "开始字符串"
separator = "分隔符"
close = "结束字符串" --><selectid="selectUser"resultType="User">
SELECT *
FROM User
WHERE ID in
<foreachitem="item"index="index"collection="list"open="("separator=","close=")">
#{item}
</foreach></select>
5、bind
<!-- bind可以创建一个变量并将其绑定到上下文 --><selectid="selectUser"resultType="user"><bindname="pattern"value="'%' + _parameter.getTitle() + '%'"/>
SELECT * FROM User
WHERE name LIKE #{pattern}
</select>
6、xml中的timestamp比较
第一种写法:
原符号 < <= > >= & ' "
替换符号 <<= >>= &'"
例如:sql如下:
create_date_time >= #{startTime} and create_date_time <= #{endTime}
第二种写法:
大于等于
<![CDATA[ >= ]]>
小于等于
<![CDATA[ <= ]]>
例如:sql如下:
create_date_time <![CDATA[ >= ]]> #{startTime} and create_date_time <![CDATA[ <= ]]> #{endTime}
<selectid="getUser"resultType="java.lang.String">
select name from user
where birthday < TO_TIMESTAMP(#{start}, 'yyyy-mm-dd hh24:mi:ss')
and birthday >= TO_TIMESTAMP(#{end}, 'yyyy-mm-dd hh24:mi:ss')
order by start desc LIMIT 1;
</select>
7、@Param
@Param是MyBatis所提供的(org.apache.ibatis.annotations.Param),作为Dao层的注解,作用是用于传递参数,从而可以与SQL中的的字段名相对应,一般在2=<参数数<=5时使用最佳。
(1)原始的方法
当只有一个参数时,没什么好说的,传进去一个值也只有一个参数可以匹配。当存在多个参数时,传进去的值就区分不开了,这时可以考虑用Map,例如接口
public List<Role> findRoleByMap(Map<String, Object> parameter);
<selectid="findRoleByMap"parameterType="map"resultType="role">
SELECT id,name FROM t_role
WHERE roleName=#{roleName}
AND note=#{note}
<select>
(2) 使用@Param
很明显上面的缺点就在于可读性差,每次必须阅读他的键,才能明白其中的作用,并且不能限定其传递的数据类型,下面是使用@Param的情况,需要将接口改为
public List<Role> findRoleByAnnotation(@Param("roleName") String roleName, @Param("note") String note);
这样我们就可以直接传入对应的值了。
当然也可以使用Java Bean来传递多个参数,定义一个POJO
publicclassRoleParam{privateString roleName;privateString note;/*getter和setter*/}
此时接口就变为
publicList<Role>findRoleByBean(RoleParam role);
这样对应的xml文件与1处的区别就在于id和parameterType发生了变化,id对应的方法和parameterType对应该类的权限定名。
而使用更多的场景可能是这样的,对应多个POJO
publicList<Role>findRoleByMix(@Param("roleP")RoleParam role,@Param("permissionP")PermissionParam permission);
这样就可以进行如下映射
<selectid="findRoleByMix"resultType="role">
SELECT id,name FROM t_role
WHERE roleName=#{roleP.roleName}
AND note=#{rolep.note}
AND level=#{permissionP.level}
<select>
注意此时并不需要写出parameterType属性,Mybatis会进行自动搜索。
(3)总结
- 当你不使用@Param注解来声明参数时,必须使用使用 #{}方式;
- 便于传多个参数;
- 类似于别名之类的功能;
十、批量插入
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPEmapperPUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mappernamespace="com.center.manager.mapper.FundMapper"><insertid="insertForeach"parameterType="java.util.List"useGeneratedKeys="false">
insert into fund
( id,fund_name,fund_code,date_x,data_y,create_by,create_date,update_by,update_date,remarks,del_flag)
values
<foreachcollection="list"item="item"index="index"separator=",">
(
#{item.id},
#{item.fundName},
#{item.fundCode},
#{item.dateX},
#{item.dataY},
#{item.createBy},
#{item.createDate},
#{item.updateBy},
#{item.updateDate},
#{item.remarks},
#{item.delFlag}
)
</foreach></insert></mapper>
十一、useGeneratedKeys参数
1、在settings元素中设置useGeneratedKeys参数
对于支持自动生成记录主键的数据库,如:MySQL,SQL Server,此时设置useGeneratedKeys参数值为true,在执行添加记录之后可以获取到数据库自动生成的主键ID。
实际上,在settings元素中设置useGeneratedKeys是一个全局参数,但是只会对接口映射器产生影响,对xml映射器不起效。
<settings><!--
允许JDBC支持自动生成主键,需要驱动兼容。
如果设置为true则这个设置强制使用自动生成主键,
尽管一些驱动不能兼容但仍可正常工作(比如 Derby)。 --><settingname="useGeneratedKeys"value="true"/></settings>
此时,在接口映射中添加记录之后将返回主键ID。
public interface UserMapper {
// 受全局useGeneratedKeys参数控制,添加记录之后将返回主键id
@Insert("insert into user(id,name,age) values(#{id},#{name},#{age})")
Integer insertUser(User user);
}
另外,在settings元素中设置的全局useGeneratedKeys参数对于xml映射器无效。如果希望在xml映射器中执行添加记录之后返回主键ID,则必须在xml映射器中明确设置useGeneratedKeys参数值为true。
2、在xml映射器中配置useGeneratedKeys参数
<!-- 插入数据:返回记录的id值 --><insertid="insertUser"parameterType="com.guor.bean.User"useGeneratedKeys="true"keyProperty="id"keyColumn="id">
insert into user(id,name,age) values(#{id},#{name},#{age})
</insert>
xml映射器中配置的useGeneratedKeys参数只会对xml映射器产生影响,且在settings元素中设置的全局useGeneratedKeys参数值对于xml映射器不产生任何作用。
3、在接口映射器中设置useGeneratedKeys参数
// 设置useGeneratedKeys为true,// 返回数据库自动生成的记录主键id@Options(useGeneratedKeys =true, keyProperty ="id",
keyColumn ="id")@Insert("insert into user(id,name,age) values(#{id},#{name},#{age})")IntegerinsertUser(User user);
请注意如果此时在接口映射器中又明确设置了useGeneratedKeys参数,那么注解映射器中的useGeneratedKeys参数值将覆盖settings元素中设置的全局useGeneratedKeys参数值。
举个例子:先在settings元素中设置全局useGeneratedKeys参数值为true,再在接口映射器中设置useGeneratedKeys参数值为false,添加记录之后将不能返回注解ID。
十二、MyBatis xml文件中postgres数据库字符串转timestamp写法
<selectid="getName"resultType="java.lang.String">
SELECT name
FROM user
WHERE birthdaey < TO_TIMESTAMP(#{start}, 'yyyy-mm-dd hh24:mi:ss')
AND birthdaey >= TO_TIMESTAMP(#{end}, 'yyyy-mm-dd hh24:mi:ss')
ORDER BY birthdaey DESC
LIMIT 1;
</select>
十三、鉴别器
<resultMaptype="com.gong.mybatis.bean.Employee"id="MyEmpDis"><idcolumn="id"property="id"/><resultcolumn="last_name"property="lastName"/><resultcolumn="gender"property="gender"/><resultcolumn="email"property="email"/><discriminatorjavaType="string"column="gender"><casevalue="0"resultType="com.gong.mybatis.bean.Employee"><associationproperty="dept"select="com.gong.mybatis.dao.DepartmentMapper.getDeptById"column="d_id"></association></case><casevalue="1"resultType="com.gong.mybatis.bean.Employee"><idcolumn="id"property="id"/><resultcolumn="last_name"property="lastName"/><resultcolumn="gender"property="gender"/><resultcolumn="last_name"property="email"/></case></discriminator></resultMap><selectid="getEmpByIdStep"resultMap="MyEmpDis">
select * from tbl_employee where id=#{id}
</select>
版权归原作者 哪 吒 所有, 如有侵权,请联系我们删除。