百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

为什么90%的开发者放弃使用Hibernate,而选择MyBatis?

liebian365 2024-10-23 13:51 2 浏览 0 评论

一、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劣势

  1. 难以使用数据库的一些功能
  2. 满足不了程序对cache的需求
  3. 耦合度高
  4. debug难
  5. hibernate更新大批量数据难度高
  6. hibernate删除大批量数据难度高

五、mybatis特点

  1. 简单易学:本身就很小且简单,没有任何第三方依赖,引入jar包,配置xml即可。
  2. 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
  3. 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
  4. 提供映射标签,支持对象与数据库的orm字段关系映射。
  5. 提供对象关系映射标签,支持对象关系组建维护。
  6. 提供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 – 可被其他语句引用的可重用语句块

<sql id="valid"> where valid = 1 </sql>

<select id = 'queryUser'>select * from user <include refid = 'valid'></include>

2、insert – 映射插入语句

<insert id = "saveUser">insert into User (id,name,sex) values (#{id},#{name},#{sex})<insert>

3、update – 映射更新语句

<update id="updateUser">

update User set

name = #{name},

sex= #{sex}

where id = #{id}

</update>

4、delete – 映射删除语句

<delete id="deleteUser">

delete from User where id = #{id}

</delete>

九、动态sql标签

1、if

<select id="findUserByName"

resultType="User">

SELECT * FROM User

WHERE valid = 1

<if test="name!= null">

AND name like #{name}

</if>

</select>

2、choose (when, otherwise)

<select id="findUser"

resultType="User">

SELECT * FROM User WHERE age = 26

<choose>

<when test="name!= null">

AND name like #{name}

</when>

<when test="sex!= null ">

AND sex like #{sex}

</when>

<otherwise>

AND valid = 1

</otherwise>

</choose>

</select>

3、trim (where, set)

<!-- prefixOverrides 属性会忽略通过管道分隔的文本序列

(注意此例中的空格也是必要的)。它的作用是移除所有指定

在prefixOverrides 属性中的内容,并且插入 prefix

属性中指定的内容。-->

<trim prefix="WHERE" prefixOverrides="AND |OR ">

...

</trim>

<!-- set 元素会动态前置

SET 关键字,同时也会删掉无关的逗号 -->

<trim prefix="SET" suffixOverrides=",">

...

</trim>

4、foreach

<!-- collection="要遍历的集合"

item = "可以在元素体内使用的集合项"

index = "索引"

open = "开始字符串"

separator = "分隔符"

close = "结束字符串" -->

<select id="selectUser" resultType="User">

SELECT *

FROM User

WHERE ID in

<foreach item="item" index="index" collection="list"

open="(" separator="," close=")">

#{item}

</foreach>

</select>

5、bind

<!-- bind可以创建一个变量并将其绑定到上下文 -->

<select id="selectUser" resultType="user">

<bind name="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}

<select id="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);

<select id="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

public class RoleParam {

private String roleName;

private String note;

/*getter和setter*/

}

此时接口就变为

public List<Role> findRoleByBean(RoleParam role);

这样对应的xml文件与1处的区别就在于id和parameterType发生了变化,id对应的方法和parameterType对应该类的权限定名。

而使用更多的场景可能是这样的,对应多个POJO

public List<Role> findRoleByMix(@Param("roleP") RoleParam role, @Param("permissionP") PermissionParam permission);

这样就可以进行如下映射

<select id="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" ?>

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="com.center.manager.mapper.FundMapper">

<insert id="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

<foreach collection="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)。 -->

<setting name="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值 -->

<insert id="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})")

Integer insertUser(User user);

请注意如果此时在接口映射器中又明确设置了useGeneratedKeys参数,那么注解映射器中的useGeneratedKeys参数值将覆盖settings元素中设置的全局useGeneratedKeys参数值。

举个例子:先在settings元素中设置全局useGeneratedKeys参数值为true,再在接口映射器中设置useGeneratedKeys参数值为false,添加记录之后将不能返回注解ID。

十二、MyBatis xml文件中postgres数据库字符串转timestamp写法

<select id="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>

十三、鉴别器

<resultMap type="com.gong.mybatis.bean.Employee" id="MyEmpDis">

<id column="id" property="id"/>

<result column="last_name" property="lastName"/>

<result column="gender" property="gender"/>

<result column="email" property="email"/>

<discriminator javaType="string" column="gender">

<case value="0" resultType="com.gong.mybatis.bean.Employee">

<association property="dept" select="com.gong.mybatis.dao.DepartmentMapper.getDeptById"

column="d_id">

</association>

</case>

<case value="1" resultType="com.gong.mybatis.bean.Employee">

<id column="id" property="id"/>

<result column="last_name" property="lastName"/>

<result column="gender" property="gender"/>

<result column="last_name" property="email"/>

</case>

</discriminator>

</resultMap>

<select id="getEmpByIdStep" resultMap="MyEmpDis">

select * from tbl_employee where id=#{id}

</select>

相关推荐

快递查询教程,批量查询物流,一键管理快递

作为商家,每天需要查询许许多多的快递单号,面对不同的快递公司,有没有简单一点的物流查询方法呢?小编的回答当然是有的,下面随小编一起来试试这个新技巧。需要哪些工具?安装一个快递批量查询高手快递单号怎么快...

一键自动查询所有快递的物流信息 支持圆通、韵达等多家快递

对于各位商家来说拥有一个好的快递软件,能够有效的提高自己的工作效率,在管理快递单号的时候都需要对单号进行表格整理,那怎么样能够快速的查询所有单号信息,并自动生成表格呢?1、其实方法很简单,我们不需要一...

快递查询单号查询,怎么查物流到哪了

输入单号怎么查快递到哪里去了呢?今天小编给大家分享一个新的技巧,它支持多家快递,一次能查询多个单号物流,还可对查询到的物流进行分析、筛选以及导出,下面一起来试试。需要哪些工具?安装一个快递批量查询高手...

3分钟查询物流,教你一键批量查询全部物流信息

很多朋友在问,如何在短时间内把单号的物流信息查询出来,查询完成后筛选已签收件、筛选未签收件,今天小编就分享一款物流查询神器,感兴趣的朋友接着往下看。第一步,运行【快递批量查询高手】在主界面中点击【添...

快递单号查询,一次性查询全部物流信息

现在各种快递的查询方式,各有各的好,各有各的劣,总的来说,还是有比较方便的。今天小编就给大家分享一个新的技巧,支持多家快递,一次能查询多个单号的物流,还能对查询到的物流进行分析、筛选以及导出,下面一起...

快递查询工具,批量查询多个快递快递单号的物流状态、签收时间

最近有朋友在问,怎么快速查询单号的物流信息呢?除了官网,还有没有更简单的方法呢?小编的回答当然是有的,下面一起来看看。需要哪些工具?安装一个快递批量查询高手多个京东的快递单号怎么快速查询?进入快递批量...

快递查询软件,自动识别查询快递单号查询方法

当你拥有多个快递单号的时候,该如何快速查询物流信息?比如单号没有快递公司时,又该如何自动识别再去查询呢?不知道如何操作的宝贝们,下面随小编一起来试试。需要哪些工具?安装一个快递批量查询高手快递单号若干...

教你怎样查询快递查询单号并保存物流信息

商家发货,快递揽收后,一般会直接手动复制到官网上一个个查询物流,那么久而久之,就会觉得查询变得特别繁琐,今天小编给大家分享一个新的技巧,下面一起来试试。教程之前,我们来预览一下用快递批量查询高手...

简单几步骤查询所有快递物流信息

在高峰期订单量大的时候,可能需要一双手当十双手去查询快递物流,但是由于逐一去查询,效率极低,追踪困难。那么今天小编给大家分享一个新的技巧,一次能查询多个快递单号的物流,下面一起来学习一下,希望能给大家...

物流单号查询,如何查询快递信息,按最后更新时间搜索需要的单号

最近有很多朋友在问,如何通过快递单号查询物流信息,并按最后更新时间搜索出需要的单号呢?下面随小编一起来试试吧。需要哪些工具?安装一个快递批量查询高手快递单号若干怎么快速查询?运行【快递批量查询高手】...

连续保存新单号功能解析,导入单号查询并自动识别批量查快递信息

快递查询已经成为我们日常生活中不可或缺的一部分。然而,面对海量的快递单号,如何高效、准确地查询每一个快递的物流信息,成为了许多人头疼的问题。幸运的是,随着科技的进步,一款名为“快递批量查询高手”的软件...

快递查询教程,快递单号查询,筛选更新量为1的单号

最近有很多朋友在问,怎么快速查询快递单号的物流,并筛选出更新量为1的单号呢?今天小编给大家分享一个新方法,一起来试试吧。需要哪些工具?安装一个快递批量查询高手多个快递单号怎么快速查询?运行【快递批量查...

掌握批量查询快递动态的技巧,一键查找无信息记录的两种方法解析

在快节奏的商业环境中,高效的物流查询是确保业务顺畅运行的关键。作为快递查询达人,我深知时间的宝贵,因此,今天我将向大家介绍一款强大的工具——快递批量查询高手软件。这款软件能够帮助你批量查询快递动态,一...

从复杂到简单的单号查询,一键清除单号中的符号并批量查快递信息

在繁忙的商务与日常生活中,快递查询已成为不可或缺的一环。然而,面对海量的单号,逐一查询不仅耗时费力,还容易出错。现在,有了快递批量查询高手软件,一切变得简单明了。只需一键,即可搞定单号查询,一键处理单...

物流单号查询,在哪里查询快递

如果在快递单号多的情况,你还在一个个复制粘贴到官网上手动查询,是一件非常麻烦的事情。于是乎今天小编给大家分享一个新的技巧,下面一起来试试。需要哪些工具?安装一个快递批量查询高手快递单号怎么快速查询?...

取消回复欢迎 发表评论: