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.

参考:  mybatis配置log4j不输出日志问题 

 

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 文件里 < (小于)号 , >(大于)号 ,会被认为是括号,需要额外转义,
解决办法 : 将 < 号换成 &lt; > 号 换成&gt;

 

 

 

There is no getter for property named ‘xxx’ in ‘class java.lang.String异常

There is no getter for property named ‘xxx’ in ‘class java.lang.String异常==>https://blog.csdn.net/douju/article/details/121959203

 

制造异常:
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>"})

第二种方法:使用转移字符。

符号 转义字符
< &lt;
<= &lt;=
> &gt;
>= &gt;=

如下:

@Select({"<script> ",
			"select * from coupon where over &lt;= #{price} and startTime &lt;= now() and now() &lt;= 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

 

posted @ 2017-11-30 14:16  苦涩泪滴  阅读(145)  评论(1)    收藏  举报