一、这就是mybatis使用广泛的原因
1、mybatis封装了jdbc,在当前的项目中的运用中已经相当广泛。
2、Mybatis是一个开源的轻量级半自动化ORM框架,使得面向对象应用程序与关系数据库的映射变得更加容易。
3、MyBatis使用xml描述符或注解将对象与存储过程或SQL语句相结合。Mybatis最大优点是应用程序与Sql进行解耦,sql语句是写在Xml Mapper文件中。强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器
4、支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer2005、SQLServer 等多种数据库
5、支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
6、支持关键词自动转义:支持数据库关键词(order、key……)自动转义,还可自定义关键词
7、内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,有超多自定义配置等
8、内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
9、内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询/
10、内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
内置 Sql 注入剥离器:支持 Sql 注入剥离,有效预防 Sql 注入攻击
二、常见的报错和解决办法(坑点)
1、映射异常,初始化失败
org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: org.apache.ibatis.reflection.ReflectionException: Error instantiating class com.bossli.bean.User with invalid types () or values (). Cause: java.lang.NoSuchMethodException: com.bossli.bean.User.<init>()
### The error may exist in sqlmapper.xml
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: select * from a01
Caused by: java.lang.NoSuchMethodException: com.bossli.bean.User.<init>()
at java.lang.Class.getConstructor0(Class.java:2892)
at java.lang.Class.getDeclaredConstructor(Class.java:2058)
at org.apache.ibatis.reflection.factory.DefaultObjectFactory.instantiateClass(DefaultObjectFactory.java:57)
... 46 more
本人在这里遇到的一个错误就是下午恰代码,头脑一发热,将此处
<?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.joyoung.cloud.moudles.system.dao.SysCompanyInoutDetailDao">
<!-- 可根据自己的需求,是否要使用 -->
<resultMap type="com.joyoung.cloud.security.common.entity.system.SysCompanyInoutDetail" id="sysCompanyInoutDetailMap">
<result property="id" column="id"/>
<result property="companyId" column="company_id"/>
<result property="accountType" column="account_type"/>
<result property="account" column="account"/>
<result property="optType" column="opt_type"/>
<result property="optId" column="opt_id"/>
<result property="optMsg" column="opt_msg"/>
<result property="crtTime" column="crt_time"/>
<result property="crtUser" column="crt_user"/>
<result property="crtName" column="crt_name"/>
<result property="crtHost" column="crt_host"/>
<result property="updTime" column="upd_time"/>
<result property="updUser" column="upd_user"/>
<result property="updName" column="upd_name"/>
<result property="updHost" column="upd_host"/>
<result property="delFlag" column="del_flag"/>
<association property="sysCompany" column="company_id" select="selectCompanyById"/>
</resultMap>
</mapper>
resultmap里面的type写成了命名空间的名字,非常粗心。导致接口测试一直出错,还找不出原因,程序员是个精细活二,得精细。
另外在查资料也看到大家的一些解决办法
原来是由于我的Bean没有无参构造器,加入无参构造函数后,错误消失。
也就是说mybatis在创建bean映射的时候需要无参的构造其来构造对象,然后才进行赋值操作。
因此,Bean必须要有无参构造函数才能正确映射。
不过这个我还没有遇到过
2、org.apache.ibatis.reflection.ReflectionException: There is no getter for propert
这也是映射异常的一种表现,表明当前字段跟表里的字段映射不到。所以这里一般在架构设计的时候都会考虑到这一点。
2-1:在application.yml文件中开启mybatis的驼峰命令匹配:
mybatis:
mapper-locations: "classpath*:mapper/**/*.xml"
type-aliases-package: com.joyoung.cloud.moudles.system.entity
//开启驼峰命名
configuration:
map-underscore-to-camel-case: true
而后只要遵守驼峰命名的语法规则,一般都不需要在映射文件里面设置数据库字段和实体类属性的匹配了。
2-2:解决方法:在参数前加@Param标签
public List<Userinfo> findAll(@Param("sname") String sname);
List<CommonsMachineLog> getLog(@Param(value = "code") String code,
@Param(value = "appSn") String appSn,
@Param(value = "machineSn") String machineSn);
void saveTerminal(@Param("sysTerminal") SysTerminal sysTerminal);
2-3:通过resultMap映射关系,映射表的字段和实体类的属性
<!-- 可根据自己的需求,是否要使用 -->
<resultMap type="com.joyoung.cloud.security.common.entity.system.SysChannelSaleRange" id="sysChannelSaleRangeMap">
<result property="id" column="id"/>
<result property="channelId" column="channel_id"/>
<result property="saleRangeId" column="sale_range_id"/>
<result property="crtTime" column="crt_time"/>
<result property="crtUser" column="crt_user"/>
<result property="crtName" column="crt_name"/>
<result property="crtHost" column="crt_host"/>
<result property="updTime" column="upd_time"/>
<result property="updUser" column="upd_user"/>
<result property="updName" column="upd_name"/>
<result property="updHost" column="upd_host"/>
<result property="delFlag" column="del_flag"/>
</resultMap>
<resultMap type="com.joyoung.cloud.security.common.entity.system.SysMachineModel" id="SysMachineModelMap">
<result property="id" column="id" jdbcType="VARCHAR"/>
<result property="categoryId" column="category_id" jdbcType="VARCHAR"/>
<result property="code" column="code" jdbcType="VARCHAR"/>
<result property="name" column="name" jdbcType="VARCHAR"/>
<result property="seq" column="seq" jdbcType="INTEGER"/>
<result property="remark" column="remark" jdbcType="VARCHAR"/>
<result property="crtTime" column="crt_time" jdbcType="TIMESTAMP"/>
<result property="crtUser" column="crt_user" jdbcType="VARCHAR"/>
<result property="crtName" column="crt_name" jdbcType="VARCHAR"/>
<result property="crtHost" column="crt_host" jdbcType="VARCHAR"/>
<result property="updTime" column="upd_time" jdbcType="TIMESTAMP"/>
<result property="updUser" column="upd_user" jdbcType="VARCHAR"/>
<result property="updName" column="upd_name" jdbcType="VARCHAR"/>
<result property="updHost" column="upd_host" jdbcType="VARCHAR"/>
<result property="delFlag" column="del_flag" jdbcType="INTEGER"/>
<association property="category" column="category_id" select="selectCategoryByModel"/>
</resultMap>
2-4:通过SQL语句来控制属性和字段的对应关系
<select id="findCpcnPayRateList" parameterType="com.joyoung.cloud.moudles.pay.zcpcn.vo.CpcnPayRateVo" resultType="com.joyoung.cloud.moudles.pay.zcpcn.vo.CpcnPayRateVo">
SELECT cpr.`company_id`,
com.`co_name` AS "companyName",
ter.`id` AS "terminalId",
ter.`name` AS "terminalName",
cpr.`machine_id`,
mac.`code` AS "machineCode",
cpr.`order_id`,
cpr.`order_num`,
cpr.`payment_no`,
cpr.`order_amount`,
cpr.`status`,
cpr.`company_rate`,
cpr.`company_rate_deduct`,
cpr.`company_record_amount`,
cpr.`deal_check`,
cpr.`crt_time`,
cpr.`crt_user`,
cpr.`crt_name`
FROM `as_cpcn_pay_rate` cpr
LEFT JOIN `sys_company` com ON com.`id` = cpr.`company_id`
LEFT JOIN `sys_terminal` ter ON ter.id = cpr.`terminal_id`
LEFT JOIN `sys_machine` mac ON mac.`id` = cpr.`machine_id`
WHERE cpr.`del_flag` = 0
<if test="companyId !=null and companyId !=''">
and cpr.`company_id` = #{companyId}
</if>
<if test="terminalId !=null and terminalId !=''">
and ter.`id` = #{terminalId}
</if>
<if test="machineId !=null and machineId !=''">
and cpr.`machine_id` = #{machineId}
</if>
<if test="status !=null and status !=''">
and cpr.`status` = #{status}
</if>
<if test="companyName !=null and companyName !=''">
and com.`co_name` like CONCAT('%', #{companyName}, '%')
</if>
<if test="terminalName !=null and terminalName !=''">
and ter.`name like CONCAT('%', #{terminalName}, '%')
</if>
<if test="machineCode !=null and machineCode !=''">
and mac.`code` like CONCAT('%', #{machineCode}, '%')
</if>
<if test="orderNum !=null and orderNum !=''">
and cpr.`order_num` like CONCAT('%', #{orderNum}, '%')
</if>
<if test="paymentNo !=null and paymentNo !=''">
and cpr.`payment_no` like CONCAT('%', #{paymentNo}, '%')
</if>
ORDER BY cpr.`crt_time` DESC
</select>
总结:其实就是熟练度的问题,一般老手很少犯这种问题,开发过程中最重要的其实就是保持头脑清醒、仔细仔细在仔细