mybatis book 已迁移到语雀
20240401已迁移至语雀 https://www.yuque.com/puredream/windsnow/mybatis_book
mybatis中xml配置说明
1.foreach简单介绍:
foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合。
foreach元素的属性主要有item,index,collection,open,separator,close。
item表示集合中每一个元素进行迭代时的别名,
index指定一个名字,用于表示在迭代过程中,每次迭代到的位置,
open表示该语句以什么开始,
separator表示在每次进行迭代之间以什么符号作为分隔符,
close表示以什么结束,
collection属性是在使用foreach的时候最关键的也是最容易出错的,该属性是必须指定的,但是在不同情况下,该属性的值是不一样的,主要有一下3种情况:
(1)如果传入的是单参数且参数类型是一个List的时候,collection属性值为list .
(2)如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array .
(3)如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可以封装成map,实际上如果你在传入参数的时候,在MyBatis里面也是会把它封装成一个Map的,map的key就是参数名,所以这个时候collection属性值就是传入的List或array对象在自己封装的map里面的key.
2.实践-实体类
public class Employees {
private Integer employeeId;
private String firstName;
private String lastName;
private String email;
private String phoneNumber;
private Date hireDate;
private String jobId;
private BigDecimal salary;
private BigDecimal commissionPct;
private Integer managerId;
private Short departmentId;
}
3.实践-Mapper
public interface EmployeesMapper {
List<Employees> getEmployeesListParams(List<String> employeeIds);
List<Employees> getEmployeesArrayParams(String[] employeeIds);
List<Employees> getEmployeesMapParams(Map<String,Object> params);
}
4.实践-XML
<!--List:forech中的collection属性类型是List,collection的值必须是:list,item的值可以随意,Dao接口中参数名字随意 -->
<select id="getEmployeesListParams" resultType="Employees">
select *
from EMPLOYEES e
where e.EMPLOYEE_ID in
<foreach collection="list" item="employeeId" index="index"
open="(" close=")" separator=",">
#{employeeId}
</foreach>
</select>
<!--Array:forech中的collection属性类型是array,collection的值必须是:list,item的值可以随意,Dao接口中参数名字随意 -->
<select id="getEmployeesArrayParams" resultType="Employees">
select *
from EMPLOYEES e
where e.EMPLOYEE_ID in
<foreach collection="array" item="employeeId" index="index"
open="(" close=")" separator=",">
#{employeeId}
</foreach>
</select>
<!--Map:不单单forech中的collection属性是map.key,其它所有属性都是map.key,比如下面的departmentId -->
<select id="getEmployeesMapParams" resultType="Employees">
select *
from EMPLOYEES e
<where>
<if test="departmentId!=null and departmentId!=''">
e.DEPARTMENT_ID=#{departmentId}
</if>
<if test="employeeIdsArray!=null and employeeIdsArray.length!=0">
AND e.EMPLOYEE_ID in
<foreach collection="employeeIdsArray" item="employeeId"
index="index" open="(" close=")" separator=",">
#{employeeId}
</foreach>
</if>
</where>
</select>
MyBatis传入参数为list、数组、map写法==>https://blog.csdn.net/s592652578/article/details/52871884
mybatis的log4j为什么不输出日志
mybatis会以下从上到下的优先级取其中一个日志作为输出器
- SLF4J
- Apache Commons Logging
- Log4j 2
- Log4j
- JDK logging
所以如果您的包里面含了slf4j-api-1.7.16.jar 那么会以SLF4J为标准,而无视log4j,此时如果还想让Log4j生效,就得添加slf4j对log4j的支持jar包slf4j-log4j12-1.7.16.jar.
MapperScannerConfigurer用法
在springmvc与mybatis整合时,需要对每一个mapper定义对应的一个MapperFactoryBean,可以使用MapperScannerConfigurer自动扫描mapper,然后自动为我们注册对应的MapperFactoryBean对象。 例如:
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="annotationClass" value="org.springframework.stereotype.Repository" /> <property name="basePackage" value="com.baidu.www" /> </bean>
basePackage表示需要扫描的包,annotationClass表示需要扫描该包下有该的注解的类。
mapperLocations配置的问题
本小节完全参考自 : mybatis 整合spring之mapperLocations配置的问题--https://www.cnblogs.com/1xin1yi/p/7373739.html
今天尝试spring整合mybatis时遇到这么一个问题,就是在配置sqlSessionFactory时是否要配置mapperLocations的问题。
<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="datasource"></property>
<property name="typeAliasesPackage" value="com.fan.entity"/>
<!-- 当mybatis的xml文件和mapper接口不在相同包下时,需要用mapperLocations属性指定xml文件的路径。
*是个通配符,代表所有的文件,**代表所有目录下 -->
<property name="mapperLocations" value="classpath:com/fan/mapper/*.xml" />
<!--也可以引入mybatis配置文件
<property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml"></property> -->
</bean>
<!-- 通过扫描的模式,扫描目录在com.lanyuan.mapper目录下的mapper-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.fan.mapper"></property>
</bean>
结论是:如果Mapper.xml与Mapper.class在同一个包下且同名,spring扫描Mapper.class的同时会自动扫描同名的Mapper.xml并装配到Mapper.class。
如果Mapper.xml与Mapper.class不在同一个包下或者不同名,就必须使用配置mapperLocations指定mapper.xml的位置。
此时spring是通过识别mapper.xml中的 <mapper namespace="com.fan.mapper.UserDao"> namespace的值来确定对应的Mapper.class的。
网上有说法,未亲测
1.mysql对语句长度有限制,Mybatis对动态语句是没有限制的
2.SqlServer对SQL的参数和语句长度是有限制的
参考:
官方api http://www.mybatis.org/mybatis-3/zh/logging.html
异常
素内容必须由格式正确的字符数据或标记组成.
原因 : MapperXXX.xml 文件里 < (小于)号 , >(大于)号 ,会被认为是括号,需要额外转义,
解决办法 : 将 < 号换成 < > 号 换成>
There is no getter for property named ‘xxx’ in ‘class java.lang.String异常
制造异常:
dao接口中的方法定义:
ArrayList<User> selectByName(String name);
Xxxmapper.xml映射配置文件中的sql:
<select id="selectByName" resultType="user" parameterType="string">
select * from users where name='${name}'
</select>
测试类中的调用:
ArrayList<User> users = userDao.selectByName("郭德纲");
解决办法:
将mapper文件中的${name}替换成MyBatis提供的固定获取单参数值方式:${_parameter} 或 ${value}
粗略解释:当传递单个值时若使用${xxx}相当于获取String类中的xxx属性(当传递单个基本数据类型参数时,都会发生这样的异常)
2.${}和#{}的主要区别
1、 ${}类似于原始JDBC中的Statement,采用的是拼接的方式生成sql语句,直接将${xxx}对应的内容直接拼接到sql语句中:
<!-- 比如${xxx}对应的内容是 Tom and 1=1 -->
<select id="selectByName" resultType="user" parameterType="string">
select * from users where name=${xxx};
</select>
上面标签中的sql就 是:
select * from users where name=Tom and 1=1;
1、很明显不能防止sql注入。
2、如果传递的值是字符串,没有自动添加引号,需要在标签中${xxx}两端自动拼接引号(单双引号)都行:’’${xxx}’’。
2、#{}类似于原始JDBC中的PrepareStatement,采用占位符的方式,生成sql语句,会将#{xxx}对应的内容当做字符串的形式填入对应的占位符位置上。
<!-- 比如${xxx}对应的内容是 Tom and 1=1 -->
<select id="selectByName" resultType="user" parameterType="string">
select * from users where name=#{xxx};
</select>
上面标签中的sql就是:
select * from users where name=‘Tom and 1=1’ ;
1、可以在很大程度上防止sql注入。
2、该方式将对应的内容当做字符串,会自动加上引号,对于非字符串数据会利用数据库的自动类型转换,不用我们处理。
3.${}和#{}的使用场景
由上面两者区别可以看出:
${}适用于拼接sql的情况下,注意拼接如=后的之值时,如果是字符串类型,需要手动拼接引号。
#{}适用于可以使用占位符的位置,大多数时候用在表示值时(比如=后面)的数据传递,对于字符串类型不需要手动拼接引号。
Mybatis总结一——日期比较,参数传递,Mapper文件的编写
1 参数传递
(1)如果不想把参数放在一个对象内封装,使用多个参数。
Dao接口层方法传参:
Integer selectAnnualSales(@Param("tenantId")String tenantId,@Param("beginDate") String beginDate,@Param("endDate")String endDate,@Param("shopCode")String shopCode,@Param("type")Integer type);
对应的Mapper.xml文件代码
<?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.bobo.springboot2mybatis.mapper.PayMapper">
<select id="selectAnnualSales" resultType="java.lang.Integer">
select sum(payment) from t_third_common_consumption
<where>
and date(create_time) BETWEEN date(#{beginDate}) and date(#{endDate})
and shop_code=#{shopCode}
and tenant_id=#{tenantId}
<choose>
<when test="type!=null">
and type = #{type} and payment >= 0
</when>
<otherwise>
and ( type = 0 or type = 1 )
</otherwise>
</choose>
</where>
</select>
</mapper>
(1) 其中,注解@Param作用使得mapper中可以直接用#{参数名}取值,如果dao层方法没有该注解,则mapper层不能用#{参数名}取值,只能用0 ,1 等索引下标对应方法中传来的参数,如#{0}。
(2)<where>元素会自动根据条件的语句数,删除无用的and。如本例会自动删除第一个and,之后的and会保留。
(3)<choose>
<when></when>
<otherwise></otherwise>
</choose>
相当与if/else。
(4)<select> 元素的属性 id 要和dao层方法名一致,且唯一。
2:日期使用
数据库中的日期格式为:yyyy-MM-dd,字段类型为date
后台传递的参数也应该符合该格式(非类型)
例如: Date date=new Date();
SimpleDateFormat format=new SimpleDateFormat ("yyyy-MM-dd");
String sDate=format.format(date); //将date转换为该格式的字符串
在mapper文件的sql语句中,比较日期的大小,要将字符串转换为date(数据库字段对应的类型,格式)类型,用date()函数。
例如 :select * from table1 where date(create_time) between date(sDate) and date(endDate);
date()会将该字符串转换为该字符串格式的日期类型。注意如果传入的日期为:yyyy-MM-dd HH:mm:ss .使用date()后会自动变成 yyyy-MM-dd . 如 2019-02-01 23:32:32 会变成 2019-02-01
————————————————
版权声明:本文为CSDN博主「崩玉~雅」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_41961316/article/details/84791594
遇见异常
异常: 元素内容必须由格式正确的字符数据或标记组成
如下图:
@Select({"<script> ",
"select * from coupon where over<=#{price} and startTime<=now() and now()<=endTime and id in ",
"<foreach item='item' index='index' collection='couponIds' open='(' separator=',' close=')'>",
"#{item}",
"</foreach>",
" order by discount desc",
"</script>"})
执行查询语句后报错: 元素内容必须由格式正确的字符数据或标记组成
原因分析:
经过查找,使用<script>标签时,内部语句会以xml的形式解析,而 < 或者 > 会被系统认为是标签,而不是大于小于号,所以才会出现问题。
解决方案:
使用<![CDATA[ SQL语句 ]]> 将含有<、>、<=、>=的sql语句包含进去。
如下:
@Select({"<script> ",
"select * from coupon where <![CDATA[over<=#{price} and startTime<=now() and now()<=endTime]]> and id in ",
"<foreach item='item' index='index' collection='couponIds' open='(' separator=',' close=')'>",
"#{item}",
"</foreach>",
" order by discount desc",
"</script>"})
第二种方法:使用转移字符。
| 符号 | 转义字符 |
|---|---|
| < | < |
| <= | <= |
| > | > |
| >= | >= |
如下:
@Select({"<script> ",
"select * from coupon where over <= #{price} and startTime <= now() and now() <= endTime and id in ",
"<foreach item='item' index='index' collection='couponIds' open='(' separator=',' close=')'>",
"#{item}",
"</foreach>",
" order by discount desc",
"</script>"})
本小节参考: https://blog.csdn.net/weixin_43982698/article/details/116133657
异常 org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)
一般原因 :
没有【mybatis.mapper-locations=classpath:mapper/xxxMapper.xml】、【mybatis.type-aliases-package=“com.example.bean”】配置属性
XML文件中的id与mapper接口中不相同
namespace 不对应,找不到返回的实体类或者文件名称不规范
springboot工程将你的资源文件拦截了,filtering为true
不支持的字符集
不支持的字符集 (在类路径中添加 orai18n.jar) ZHS16GBK
不支持的字符集 (在类路径中添加 orai18n.jar) ZHS16GBK
报错内容:
Exception in thread “main” java.sql.SQLException: 不支持的字符集 (在类路径中添加 orai18n.jar): ZHS16GBK
at oracle.sql.CharacterSetUnknown.failCharsetUnknown(CharacterSetFactoryThin.java:233)
at oracle.sql.CharacterSetUnknown.convert(CharacterSetFactoryThin.java:194)
at oracle.jdbc.driver.PhysicalConnection.throughDbCharset(PhysicalConnection.java:10402)
at oracle.jdbc.driver.PhysicalConnection.enquoteIdentifier(PhysicalConnection.java:10479)
at oracle.jdbc.driver.OracleStatement.enquoteIdentifier(OracleStatement.java:6452)
at oracle.jdbc.driver.OracleStatement.getColumnIndex(OracleStatement.java:3853)
at oracle.jdbc.driver.InsensitiveScrollableResultSet.findColumn(InsensitiveScrollableResultSet.java:270)
at oracle.jdbc.driver.GeneratedResultSet.getString(GeneratedResultSet.java:596)
at com.courage.apacheDBUtils.DBUtilsTest.main(DBUtilsTest.java:17)
解决方案:
根据报错信息提示,导入orai18n.jar或者在pom.xml中添加orai18n.jar的依赖
<!-- https://mvnrepository.com/artifact/com.oracle.database.nls/orai18n -->
<dependency>
<groupId>com.oracle.database.nls</groupId>
<artifactId>orai18n</artifactId>
<version>19.7.0.0</version>
</dependency>
————————————————
版权声明:本文为CSDN博主「出息」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44155001/article/details/120782599
springboot2和mybatis搭建
📌SpringBoot2 学习系列(一):SpringBoot2 mybatis==>https://blog.csdn.net/qq_36378416/article/details/100581506

浙公网安备 33010602011771号