parameterType:即将传入的语句参数的完全限定类名和别名。这个属性是可选项的,因为MyBatis可以推断出传入语句的具体参数,因此不建议配置该属性
flushCache:默认值为true,任何时候只要语句被调用,都会清空一级缓存和二级缓存
useGeneratedKeys默认值为false。如果设置为true,MyBatis会使用JDBC的getGeneratedKeys方法来取出由数据库内部生成的主键
keyProperty:MyBatis通过getGeneratedKeys获取主键值后将要赋值的属性名【不会更改db表中字段值】。如果希望得到多个数据库自动生成的列,属性值也可以是以逗号分隔的属性名称列表
此处<insert>中的SQL就是一个简单的INSERT语句,将所有的列都列举出来,在values中通过#{property}方式从参数中取出属性的值。
为了防止类型错误,对于一些特殊的数据类型,建议指定具体的jdbcType值。例如,icon字段指定BLOB类型,createTime指定TIMESTAMP类型
tips:
BLOB对应的类型是ByteArrayInputStream,就是二进制数据流
由于数据库区分date,time,dataTime类型,但是Java中一般都使用java.util.Date类型。因此为了保证数据类型的正确,需要手动指定日期类型,date,time,datetime对应的JDBC类型的DATE,TIME,TIMESTAMP
<insert id="insertSysUser" parameterType="user" useGeneratedKeys="true" keyProperty="id" > insert into sys_user ( user_name, user_password, user_email, icon, create_time ) values ( #{userName}, #{userPassword}, #{userEmail}, #{icon,jdbcType=BLOB}, #{createTime,jdbcType=TIMESTAMP} ) </insert>
<insert id="insertSysUser" > insert into sys_user ( user_name, user_password, user_email, icon, create_time ) values ( #{userName}, #{userPassword}, #{userEmail}, #{icon,jdbcType=BLOB}, #{createTime,jdbcType=TIMESTAMP} ) <selectKey keyColumn="id" resultType="long" keyProperty="id" order="AFTER" > select LAST_INSERT_ID() </selectKey> </insert>
selectKey标签的keyColumn、keyProperty和上面useGeneratedKeys的用法含义相同,这里的resultType用于设置返回值类型。order属性的设置和使用的数据库有关。
在MySQL数据库中,order属性设置的值是AFTER,因为当前记录的主键值在insert语句执行成功后才能获取到。
而Oracle数据库中,order的值要设置为BEFORE,这是因为Oracle中需要先从序列获取值,然后将值作为主键插入到数据库中
http://www.mybatis.org/mybatis-3/zh/configuration.html
<insert id="insertStudent" parameterType="com.czd.mybatis01.bean.Student"> INSERT stu(name)VALUES (#{name}) <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer"> SELECT LAST_INSERT_ID() </selectKey> </insert>
总体解释:将插入数据的主键返回到 user 对象中。
具体解释:
SELECT LAST_INSERT_ID():得到刚 insert 进去记录的主键值,只适用与自增主键
keyProperty:将查询到主键值设置到 parameterType 指定的对象的那个属性
order:SELECT LAST_INSERT_ID() 执行顺序,相对于 insert 语句来说它的执行顺序
resultType:指定 SELECTLAST_INSERT_ID() 的结果类型
注意点:假如你使用一条INSERT语句插入多个行, LAST_INSERT_ID() 只会返回插入的第一行数据时产生的值。比如我插入了 3 条数据,它们的 id 分别是 21,22,23.那么最后我还是只会得到 21 这个值。
http://blog.csdn.net/czd3355/article/details/71302441
insert和update操作中会常常用到自动生成主键的问题。
1、selectKey和useGeneratedKeys属性
useGeneratedKeys (insert and update only) This tells MyBatis to use the JDBC getGeneratedKeys method to retrieve keys generated internally by the database (e.g.auto increment fields in RDBMS like MySQL or SQL Server). Default: false
(( 仅 对 insert 和update有 用 ) 这 会 告 诉 MyBatis 使 用 JDBC 的 getGeneratedKeys 方法来取出由数据(比如:像 MySQL 和 SQL Server 这样的数据库管理系统的自动递增字段)内部生成的主键。默认值:false。)
2、keyProperty
(insert and update only) Identifies a property into which MyBatis will set the key value returned by
getGeneratedKeys , or by a selectKey child element of the insert statement. Default: unset .
Can be a comma separated list of property names if multiple generated columns are expected.
((仅对 insert和update有用) 标记一个属性, MyBatis会通过 getGeneratedKeys 或者通过 insert 语句的 selectKey 子元素设置它的值。默认: 不设置。)
3、keyColumn
(insert and update only) Sets the name of the column in the table with a generated key. This is only required
in certain databases (like PostgreSQL) when the key column is not the first column in the table. Can be a
comma separated list of columns names if multiple generated columns are expected.
selectKey和useGeneratedKeys使用
<insert id="insert"> <selectKey keyProperty="id" resultType="int" order="BEFORE"> <if test="_databaseId == 'oracle'"> select seq_users.nextval from dual </if> <if test="_databaseId == 'db2'"> select nextval for seq_users from sysibm.sysdummy1" </if> </selectKey> insert into users values (#{id}, #{name}) </insert>
通过selectKey在插入操作前或者操作后获取key值,做为字段插入或返回字段。(此段代码获取的序列值id作为字段值插入到users表中)
<insert id="insertAuthor" useGeneratedKeys="true" keyProperty="id"> insert into Author (username,password,email,bio) values (#{username},#{password},#{email},#{bio}) </insert>
如果数据库支持自增长主键字段(比如mysql、sql server)设置useGeneratedKeys=”true”和keyProperty,这样就可以插入主键id值
oracle则不支持自增长id,设置useGeneratedKey=”false”,如果设置true则会有报错信息。通过nextval函数,如SEQ_table.Nextval生成id
3.插入更新一条数据时,可以使用selectKey获取id操作。当做多条数据插入更新时,而selectKey只能使用一次,此时应该使用useGeneratedKeys操作。
从Mybatis源码分析selectKey和useGeneratedKeys属性的使用
http://blog.csdn.net/u013512014/article/details/53587600?utm_source=itdadao&utm_medium=referral
What is the difference between #{...} and ${...}?
MyBatis interprets #{...} as a parameter marker in a JDBC prepared statement. MyBatis interprets ${...} as string substitution. It is important to know the difference because parameter markers cannot be used in certain places in SQL statements.
For example, you cannot use a parameter marker to specify a table name.
Given the following code:
Map<String, Object> parms = new HashMap<String, Object>(); parms.put("table", "foo"); parms.put("criteria", 37); List<Object> rows = mapper.generalSelect(parms);
<select id="generalSelect" parameterType="map"> select * from ${table} where col1 = #{criteria} </select>
MyBatis will generate the following prepared statement:
select * from foo where col1 = ?
Important: note that use of ${...} (string substitution) presents a risk for SQL injection attacks. Also, string substitution can be problematical for complex types like dates. For these reasons, we recommend using the #{...} form whenever possible.
How do I code an SQL LIKE?
There are two methods. In the first (and preferred) method, you append the SQL wildcards in your Java code.
For example:
String wildcardName = "%Smi%";
List<Name> names = mapper.selectLike(wildcardName);
<select id="selectLike"> select * from foo where bar like #{value} </select>
Another method is to concatenate the wildcards in your SQL. This method is less safe than the method above because of possible SQL injection.
For example:
String wildcardName = "Smi";
List<Name> names = mapper.selectLike(wildcardName);
<select id="selectLike"> select * from foo where bar like '%' || '${value}' || '%' </select>
Important: Note the use of $ vs. # in the second example!
How do I code a batch insert?
First, code a simple insert statement like this:
<insert id="insertName"> insert into names (name) values (#{value}) </insert>
Then execute a batch in Java code like this:
List<String> names = new ArrayList<String>(); names.add("Fred"); names.add("Barney"); names.add("Betty"); names.add("Wilma"); SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); try { NameMapper mapper = sqlSession.getMapper(NameMapper.class); for (String name : names) { mapper.insertName(name); } sqlSession.commit(); } finally { sqlSession.close(); }
How can I retrieve the value of an auto generated key?
The insert method always returns an int - which is the number of rows inserted. Auto generated key values are placed into the parameter object and are available after the completion of the insert method.
For example:
<insert id="insertName" useGeneratedKeys="true" keyProperty="id"> insert into names (name) values (#{name}) </insert>
Name name = new Name(); name.setName("Fred"); int rows = mapper.insertName(name); System.out.println("rows inserted = " + rows); System.out.println("generated key value = " + name.getId());
https://github.com/mybatis/mybatis-3/wiki/FAQ#how-do-i-code-a-batch-insert
userDao-mapping.xml相当于是UserDao的实现, 同时也将User实体类与数据表User成功关联起来。
再编写一个userDao-mapping.xml (可随便命名):
userDao-mapping.xml:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//ibatis.apache.org//DTD Mapper 3.0//EN" "http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd"> <mapper namespace="com.dy.dao.UserDao"> <select id="findUserById" resultType="com.dy.entity.User" > select * from user where id = #{id} </select> </mapper>
package com.dy.entity; public class User { private int id; private String name; private String password; private int age; private int deleteFlag; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getDeleteFlag() { return deleteFlag; } public void setDeleteFlag(int deleteFlag) { this.deleteFlag = deleteFlag; } }
再编写一个UserDao 接口:
UserDao:
package com.dy.dao; import java.util.List; import com.dy.entity.User; public interface UserDao { public void insert(User user); public User findUserById (int userId); public List<User> findAllUsers(); }
http://www.cnblogs.com/dongying/p/4031382.html
注意:#与$区别: 1.#是把传入的数据当作字符串,如#field#传入的是id,则sql语句生成是这样,order by "id",这当然会报错.. 2.$传入的数据直接生成在sql里,如#field#传入的是id,则sql语句生成是这样,order by id, 这就对了. $方式一般用于传入数据库对象.例如传入表名、字段名 . #方式一般用于传入插入/更新的值或查询/删除的where条件中业务数据
http://aqxiebin.iteye.com/blog/1415578
<select>是iBatis已经映射的语句类型,就是查询了,为了配合说明,这里再介绍两个标记:<sql>和<include>,前者用来创建一个文本片段,这些片段可以组合起来创建完整的SQL语句;后者很显然就是包含的意思了。假设我们有如下代码段:
<sql id="select-user"> select * from users </sql> <sql id="select-count"> select count(*) as value from users </sql> <sql id="where-age-over-value"> <![CDATA[ where age > #value:INT# ]]> </sql> <select id="getUserAgeOver" resultClass="hashmap"> <include refid="select-user" /> <include refid="where-age-over-value" /> </select> <select id="getUserCountAgeOver" resultClass="int"> <include refid="select-count" /> <include refid="where-age-over-value" /> </select>
该部分代码展示了sql和include的使用,其中使用了CDATA段,这是因为XML标签本体中出现了于XML标签冲突的字符,这很好理解。后面两个查询就是我们执行的语句部分,程序代码可以这么来写:
List users = sqlMap.queryForList("User.getUserAgeOver","23"); System.out.println(users); int userCount = (Integer) sqlMap.queryForObject( "User.getUserCountAgeOver", "22"); System.out.println(userCount);
如果可以查询到记录,那么就会打印出来了。上面的例子中我们是用了#来标识传递的参数,#被成为占位符,这是内联参数的传递方式的一种。
<select id="getUserById" resultClass="User"> select userId, userName, password, age, mobile, mail from users where userId = #value# </select>
在程序中,用下面这些代码就能达到查询效果了。
User user = (User) sqlMap.queryForObject("User.getUserById", new Integer(1)); System.out.println(user);
#value#是告诉iBatis传递一个简单的参数,iBatis处理该语句时,将会把#value#转换为预处理参数形式,然后将这个参数的值设置为1(就是queryForObject()方法的第二个参数),之后执行该预处理语句。最后iBatis接受返回的结果,然后把它映射到一个Java对象并返回该对象,这就是sqlMap的执行过程。
下面来看另外一种内联参数形式,就是使用$作为占位符。它可以直接把参数插入到SQL语句中,这在该SQL语句被转变为参数化语句之前就执行了。如此就会留下安全隐患,它可能给SQL注入有机可乘,而且过度使用还会有性能问题,看下面这个语句:
<select id="getUserByLikeEmail" resultClass="User"> select userId, userName, password, age, mobile, email from users where email like '%$value$%' </select>
在程序中,我们可以使用如下代码来执行模糊查询:
List<User> users = sqlMap.queryForList("User.getUserByLikeEmail", "gmail");
System.out.println(users);
若要使用#方式来当占位符,那么模糊查询时可能不是那么方便,需要如下进行:email like concat('%',#value#,'%'),这是MySQL的情况。所以模糊查询使用$比较方便。
以上的查询中我们使用了resultClass这种自动结果映射,这是iBatis的一种执行机制,而我们也可以进行自定义结果映射,就是使用resultMap。如果我们在查询中两者都没有使用的话,那么iBatis执行查询但是不能返回任何东西。
当我们使用bean作为结果映射时要注意如果结果列存在于数据库而不存在于bean中,那么我们不会得到任何数据,而且执行不会报错。自动映射使用起来很方便,但是更稳健的要数外部结果映射了
http://sarin.iteye.com/blog/731655
//外部调用此方法对mybatis配置文件进行解析 public Configuration parse() { if (parsed) { throw new BuilderException("Each XMLConfigBuilder can only be used once."); } parsed = true; //从根节点configuration parseConfiguration(parser.evalNode("/configuration")); return configuration; } //此方法就是解析configuration节点下的子节点 //由此也可看出,我们在configuration下面能配置的节点为以下10个节点 private void parseConfiguration(XNode root) { try { propertiesElement(root.evalNode("properties")); //issue #117 read properties first typeAliasesElement(root.evalNode("typeAliases")); pluginElement(root.evalNode("plugins")); objectFactoryElement(root.evalNode("objectFactory")); objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); settingsElement(root.evalNode("settings")); environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory issue #631 databaseIdProviderElement(root.evalNode("databaseIdProvider")); typeHandlerElement(root.evalNode("typeHandlers")); mapperElement(root.evalNode("mappers")); } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); } } }
通过以上源码,我们就能看出,在mybatis的配置文件中:
1. configuration节点为根节点。
2. 在configuration节点之下,我们可以配置10个子节点, 分别为:
properties、
typeAliases、
plugins、
objectFactory、
objectWrapperFactory、
settings、
environments、
databaseIdProvider、
typeHandlers、
mappers
http://www.cnblogs.com/dongying/p/4031613.html
解决org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)错误
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)
一般的原因
Mapper interface和xml文件的定义对应不上,需要检查包名,namespace,函数名称等能否对应上。
按以下步骤一一执行:
1、检查xml文件所在的package名称是否和interface对应的package名称一一对应
2、检查xml文件的namespace是否和xml文件的package名称一一对应
3、检查函数名称能否对应上
4、去掉xml文件中的中文注释
5、随意在xml文件中加一个空格或者空行然后保存
注意:
在使用IDEA开发时,如果打包时*Mapper.xml没有自动复制到class输出目录的mapper类包下,则需要在pom文件中添加mybatis加载配置文件的配置!
如下:
<build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> </resource> <resource> <directory>src/main/resources</directory> </resource> </resources> </build>
http://blog.csdn.net/oMrLeft123/article/details/70239951
Could not find result map XXX 解决办法
出错代码:
<select id="selectByPartName" resultMap="com.mybatistest.common.QueryBase" parameterType="String"> SELECT * FROM manager WHERE name like CONCAT('%',# {parameters.partName},'%') </select>
异常信息如下:
org.apache.ibatis.builder.IncompleteElementException:
Could not find result map com.mybatistest.common.QueryBase
其中QueryBase为分页查询的结果对象。这个错误的意思是:返回的结果和类型不一致。
出错原因:
传进来的参数应该是QueryBase对象,其中包含了查询需要的Map参数数组,返回值类型应该是BaseResultMap,可能是一条记录也可能是多条记录。
<select id="selectByPartName" resultMap="BaseResultMap" parameterType="com.mybatistest.common.QueryBase"> SELECT * FROM manager WHERE name like CONCAT('%',#{parameters.partName},'%') </select>
https://blog.csdn.net/u011853294/article/details/51211213
Caused by: org.apache.ibatis.executor.ExecutorException:
A query was run and no Result Maps were found for the Mapped Statement 'com.hujiang.portal.read.soa.dao.user.ReadUserAppealDao.countOrders'.
It's likely that neither a Result Type nor a Result Map was specified. at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.validateResultMapsCount(DefaultResultSetHandler.java:275) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:180) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:64) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79) ~[mybatis-3.4.0.jar:3.4.0] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_144] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_144] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_144] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_144] at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:63) ~[mybatis-3.4.0.jar:3.4.0] at com.sun.proxy.$Proxy178.query(Unknown Source) ~[?:?] at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:83) ~[mybatis-3.4.0.jar:3.4.0] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_144] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_144] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_144] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_144] at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:63) ~[mybatis-3.4.0.jar:3.4.0] at com.sun.proxy.$Proxy177.query(Unknown Source) ~[?:?] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_144] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_144] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_144] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_144] at org.apache.ibatis.plugin.Invocation.proceed(Invocation.java:49) ~[mybatis-3.4.0.jar:3.4.0] at com.hujiang.basic.framework.dao.interceptor.PageInterceptor.queryByMaxLimit(PageInterceptor.java:213) ~[hujiang-framework-dao-2.1.1-RELEASE.jar:2.1.1-RELEASE] at com.hujiang.basic.framework.dao.interceptor.PageInterceptor.intercept(PageInterceptor.java:158) ~[hujiang-framework-dao-2.1.1-RELEASE.jar:2.1.1-RELEASE] at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61) ~[mybatis-3.4.0.jar:3.4.0] at com.sun.proxy.$Proxy177.query(Unknown Source) ~[?:?] at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:148) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:77) ~[mybatis-3.4.0.jar:3.4.0] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_144] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_144] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_144] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_144]
报错:
Caused by: org.apache.ibatis.reflection.ReflectionException: Could not set property 'batchIds' of 'class com.dto.response.coupon.CouponDetailResponse' with value '1003250' Cause: java.lang.IllegalArgumentException: argument type mismatch at org.apache.ibatis.reflection.wrapper.BeanWrapper.setBeanProperty(BeanWrapper.java:185) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.reflection.wrapper.BeanWrapper.set(BeanWrapper.java:59) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.reflection.MetaObject.setValue(MetaObject.java:140) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.linkObjects(DefaultResultSetHandler.java:1055) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyNestedResultMappings(DefaultResultSetHandler.java:902) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:857) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForNestedResultMap(DefaultResultSetHandler.java:820) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:312) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:287) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:183) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:64) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79) ~[mybatis-3.4.0.jar:3.4.0] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_144] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_144] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_144] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_144] at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:63) ~[mybatis-3.4.0.jar:3.4.0] at com.sun.proxy.$Proxy181.query(Unknown Source) ~[?:?] at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:83) ~[mybatis-3.4.0.jar:3.4.0] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_144] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_144] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_144] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_144] at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:63) ~[mybatis-3.4.0.jar:3.4.0] at com.sun.proxy.$Proxy180.query(Unknown Source) ~[?:?] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_144] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_144] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_144] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_144] at org.apache.ibatis.plugin.Invocation.proceed(Invocation.java:49) ~[mybatis-3.4.0.jar:3.4.0] at com.dao.interceptor.PageInterceptor.queryByMaxLimit(PageInterceptor.java:213) ~[-framework-dao-2.1.1-RELEASE.jar:2.1.1-RELEASE] at com.dao.interceptor.PageInterceptor.intercept(PageInterceptor.java:158) ~[-framework-dao-2.1.1-RELEASE.jar:2.1.1-RELEASE] at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61) ~[mybatis-3.4.0.jar:3.4.0] at com.sun.proxy.$Proxy180.query(Unknown Source) ~[?:?] at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:148) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:77) ~[mybatis-3.4.0.jar:3.4.0] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_144] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_144] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_144] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_144] at com.dao.mybatis.CustomSqlSessionTemplate$SqlSessionInterceptor.invoke(CustomSqlSessionTemplate.java:329) ~[-framework-dao-2.1.1-RELEASE.jar:2.1.1-RELEASE] ... 87 more Caused by: java.lang.IllegalArgumentException: argument type mismatch at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_144] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_144] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_144] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_144] at org.apache.ibatis.reflection.invoker.MethodInvoker.invoke(MethodInvoker.java:41) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.reflection.wrapper.BeanWrapper.setBeanProperty(BeanWrapper.java:180) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.reflection.wrapper.BeanWrapper.set(BeanWrapper.java:59) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.reflection.MetaObject.setValue(MetaObject.java:140) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.linkObjects(DefaultResultSetHandler.java:1055) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyNestedResultMappings(DefaultResultSetHandler.java:902) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:857) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForNestedResultMap(DefaultResultSetHandler.java:820) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:312) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:287) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:183) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:64) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79) ~[mybatis-3.4.0.jar:3.4.0] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_144] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_144] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_144] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_144] at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:63) ~[mybatis-3.4.0.jar:3.4.0] at com.sun.proxy.$Proxy181.query(Unknown Source) ~[?:?] at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:83) ~[mybatis-3.4.0.jar:3.4.0] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_144] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_144] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_144] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_144] at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:63) ~[mybatis-3.4.0.jar:3.4.0] at com.sun.proxy.$Proxy180.query(Unknown Source) ~[?:?] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_144] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_144] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_144] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_144] at org.apache.ibatis.plugin.Invocation.proceed(Invocation.java:49) ~[mybatis-3.4.0.jar:3.4.0] at com.dao.interceptor.PageInterceptor.queryByMaxLimit(PageInterceptor.java:213) ~[-framework-dao-2.1.1-RELEASE.jar:2.1.1-RELEASE] at com.dao.interceptor.PageInterceptor.intercept(PageInterceptor.java:158) ~[-framework-dao-2.1.1-RELEASE.jar:2.1.1-RELEASE] at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61) ~[mybatis-3.4.0.jar:3.4.0] at com.sun.proxy.$Proxy180.query(Unknown Source) ~[?:?] at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:148) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141) ~[mybatis-3.4.0.jar:3.4.0] at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:77) ~[mybatis-3.4.0.jar:3.4.0] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_144] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_144] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_144] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_144] at com.dao.mybatis.CustomSqlSessionTemplate$SqlSessionInterceptor.invoke(CustomSqlSessionTemplate.java:329) ~[-framework-dao-2.1.1-RELEASE.jar:2.1.1-RELEASE] ... 87 more
解决办法:将1:N关联中,存放多条记录的java 属性 不使用数组。 使用Collection及其子类型 都可以
环境信息:
返回一个什么样的数据结构:
import com.alibaba.fastjson.annotation.JSONField; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.util.List; /** * @author tangcheng * 2018/04/20 */ @Data public class CouponDetailResponse{ @ApiModelProperty("主键Id") private Integer id; @JSONField(jsonDirect = true) private String introUrls; private String btnCopy; private String buyUrl; private Integer[] batchIds; //此处使用数组类型,导致的报错。解决办法,改为 List<Integer> batchIds;即可 }
Mybatis中的xml 如下:
<resultMap id="detailResultMap" type="couponDetailResponse"> <id column="id" property="id" jdbcType="INTEGER"/> <result column="intro_urls" property="introUrls" jdbcType="VARCHAR"/> <result column="btn_copy" property="btnCopy" jdbcType="VARCHAR"/> <result column="buy_url" property="buyUrl" jdbcType="VARCHAR"/> <collection property="batchIds" ofType="int"> <result column="batch_id"/> </collection> </resultMap> <select id="getDetailBy" resultMap="detailResultMap"> SELECT rcp.id, rcp.intro_urls, rcp.btn_copy, rcp.buy_url, rcpb.batch_id FROM read_coupon rcp, read_coupon_activity rcpb WHERE rcp.id = rcpb.coupon_id AND rcp.id=#{id} </select>
参考:http://blog.51cto.com/zwbjava/1630250
Mybatis select返回值为map时,选取表字段的两列作为key,value
1、先看看xml文件怎么配置
<resultMap id="getAllSetDaysResult" type="HashMap"> <result property="key" column="SP_FPARAMEKEY" /> <result property="value" column="SP_FPARAMEVALUE" /> </resultMap>
来看看sql是怎么写的
<select id="getAllSetDays" resultMap="getAllSetDaysResult"> SELECT SP.FPARAMEKEY SP_FPARAMEKEY, SP.FPARAMEVALUE SP_FPARAMEVALUE FROM T_SERVER_PARAMETER SP WHERE SP.FPARAMEKEY IN ('XXX') </select>
这种情况下,返回数据结构是这样的:
List<Map<String, Double>> getAllSetDays();
List中每个Map中只存放一条记录。
如下所示的数据结构:
[{value=2, key=http://1.com/1.jpg}, {value=3, key=http://1.com/1.jpg}, {value=4, key=http://1.com/1.jpg}]
如果不写List,但select结果有两条则会报错:
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3
如果想实现在Map中存放多条记录,需要做以下调整:
思路:重写ResultHandler接口,,然后用SqlSession 的select方法,将xml里面的映射文件的返回值配置成 HashMap 就可以了
(1)沿用上面的xml配置
(2)重写org.apache.ibatis.session 中ResultHandler接口:
public class FblMapResultHandler implements ResultHandler { @SuppressWarnings("rawtypes") private final Map mappedResults = new HashMap(); @SuppressWarnings("unchecked") @Override public void handleResult(ResultContext context) { @SuppressWarnings("rawtypes") Map map = (Map) context.getResultObject(); mappedResults.put(map.get("key"), map.get("value")); // xml 配置里面的property的值,对应的列 } public Map getMappedResults() { return mappedResults; } }
(3)调用select方法:
FblMapResultHandler fbl = new FblMapResultHandler(); getSqlSession().select(NAMESPACE +"getAllSetDays",fbl); @SuppressWarnings("rawtypes") Map map =fbl.getMappedResults(); return map;
此时map里面的key,和value就是我们数据库中表中的对应的两列了.
https://blog.csdn.net/sou_liu/article/details/47755635
今天遇到一个问题,mysql数据库使用mybatis在mapper.xml写动态sql order by无法正确使用,没有报错,看日志也是传入了值
后来自己修改order by传入的值,发现对sql没有影响,说明这个sql没有正确执行
首先sql是这样写的
order by #{ORDER_BY}
外部定义是
private static final String ORDER_BY = "name ASC";
查看日志
Parameters: name ASC(String), 0(Integer), 10(Integer)
看到ORDER_BY的确传进来了,就是这个name ASC(String),但是它是String类型的,这时sql语句为 order by "name ASC",
大家可以在mysql里面直接这样写写,sql语句会执行,但是没有作用,也不会报错
下面改成
order by ${ORDER_BY}
查看日志
Parameters: 0(Integer), 10(Integer)
没有了name ASC(String) 但是结果正确执行了
网上查找资料:
(1)对于形如#{variable} 的变量,Mybatis会将其视为字符串值,在变量替换成功后,缺省地给变量值加上引号。"variable"
(2)对于形如${variable}的变量,Mybatis会将其视作直接变量,即在变量替换成功后,不会再给其加上引号。 variable
所以在动态sql中,#{variable} 需要去掉 "",比如正常sql赋值一般是这样的and name= #{name},因为是=赋值,所以会获取内容,去掉""
${variable}可以直接使用,比如order by ${name} 传入的直接是name,不带双引号,可以直接使用,
并且order by不是 =赋值,所以如果直接order by #{name},结果是order by "name",自然无法执行了
总结,#{variable} 传入字符串,可以在日志查看到传入的参数,需要赋值后使用,可以有效防止sql注入
${variable}是直接传入变量,在日志查看不到传入的变量,直接在sql中执行,无法防止sql注入
所以,尽量用#{variable}格式,如果不是类似=赋值后再使用的sql,需要使用${variable}
网上还说有<![CDATA[]]>内需要注意#与$的区别,暂时没遇到,先备注一下。
https://blog.csdn.net/Mint6/article/details/78039935
mybatis动态sql中where标签的使用
where标记的作用类似于动态sql中的set标记,他的作用主要是用来简化sql语句中where条件判断的书写的,如下所示:
<select id="selectByParams" parameterType="map" resultType="user"> select * from user <where> <if test="id != null ">id=#{id}</if> <if test="name != null and name.length()>0" >and name=#{name}</if> <if test="gender != null and gender.length()>0">and gender = #{gender}</if> </where> </select>
在上述SQL中加入ID的值为null的话,那么打印出来的SQL为:select * from user where name="xx" and gender="xx"
where 标记会自动将其后第一个条件的and或者是or给忽略掉
https://www.cnblogs.com/qiankun-site/p/5762342.html