MyBatis可以利用SQL映射文件来配置,也可以利用Annotation来设置。MyBatis提供的一些基本注解如下表所示。
注解 | 目标 | 相应的XML | 描述 |
@CacheNamespace | 类 | <cache> | 为给定的命名空间(比如类)配置缓存。属性: implemetation,eviction, flushInterval , size 和 readWrite 。 |
@CacheNamespaceRef | 类 | <cacheRef> | 参照另外一个命名空间的缓存来使用。 属性:value,也就是类的完全限定名。 |
@ConstructorArgs | 方法 | <constructor> | 收集一组结果传递给对象构造方法。 属性:value,是形式参数的数组 |
@Arg | 方法 | <arg> <idArg>
| 单独的构造方法参数,是ConstructorArgs 集合的一部分。属性:id,column,javaType,typeHandler。 id属性是布尔值,来标识用于比较的属性,和<idArg>XML 元素相似 |
@TypeDiscriminator | 方法 | <discriminator> | 一组实例值被用来决定结果映射的表 现。属性:Column, javaType , jdbcType typeHandler,cases。 cases属性就是实例的数组。 |
@Case | 方法 | <case> | 单独实例的值和它对应的映射。属性:value ,type ,results 。 Results 属性是结果数组,因此这个注解和实际的ResultMap 很相似,由下面的 Results注解指定 |
@Results | 方法 | <resultMap> | 结果映射的列表,包含了一个特别结果 列如何被映射到属性或字段的详情。 属性:value ,是Result注解的数组 |
@Result | 方法 | <result> <id> | 在列和属性或字段之间的单独结果映 射。属性:id ,column , property , javaType ,jdbcType ,type Handler , one,many。id 属性是一个布尔值,表 示了应该被用于比较的属性。one 属性是单独的联系,和 <association> 相似,而many 属性是对集合而言的,和 <collection>相似。 |
@One | 方法 | <association> | 复杂类型的单独属性值映射。属性: select,已映射语句(也就是映射器方 法)的完全限定名,它可以加载合适类 型的实例。注意:联合映射在注解 API 中是不支持的。 |
@Many | 方法 | <collection> | 复杂类型的集合属性映射。属性: select,是映射器方法的完全限定名,它可加载合适类型的一组实例。注意:联合映射在Java注解中是不支持的。 |
@Options | 方法 | 映射语句的属性 | 这个注解提供访问交换和配置选项的宽广范围,它们通常在映射语句上作为属性出现。而不是将每条语句注解变复杂,Options 注解提供连贯清晰的方式来访问它们。属性:useCache=true, flushCache=false, resultSetType=FORWARD_ONLY, statementType=PREPARED, fetchSize= -1,timeout=-1 , useGeneratedKeys=false , keyProperty=”id“。 理解Java 注解是很重要的,因为没有办法来指定“null ”作为值。因此,一旦你使用了Options注解,语句就受所有默认值的支配。要注意什么样的默认值来避免不期望的行为 |
@Insert @Update @Delete | 方法 | <insert> <update> <delete> | 这些注解中的每一个代表了执行的真实 SQL。它们每一个都使用字符串数组(或单独的字符串)。如果传递的是字符串数组,它们由每个分隔它们的单独空间串联起来。属性:value,这是字符串数组用来组成单独的SQL语句 |
@InsertProvider @UpdateProvider @DeleteProvider @SelectProvider | 方法 | <insert> <update> <delete> <select> 允许创建动态 SQL。 | 这些可选的SQL注解允许你指定一个 类名和一个方法在执行时来返回运行 的SQL。基于执行的映射语句, MyBatis 会实例化这个类,然后执行由 provider 指定的方法. 这个方法可以选择性的接 受参数对象作为它的唯一参数,但是必 须只指定该参数或者没有参数。属性: type,method。type 属性是类的完全限定名。method 是该类中的那个方法名。 |
@Param | 参数 | N/A | 当映射器方法需多个参数,这个注解可以被应用于映射器方法参数来给每个参数一个名字。否则,多参数将会以它们的顺序位置来被命名。比如 #{1},#{2} 等,这是默认的。 使用@Param(“person”),SQL中参数应该被命名为#{person}。 |
这些注解都是运用到传统意义上映射器接口中的方法、类或者方法参数中的。
今天主要介绍两种使用注解的方式。
一种是直接在映射器接口中写SQL语句,一种是利用SqlBuilder来创建SQL再由映射器接口来调用
准备前提:
1,配置常规的MyBatis主配置文件,即各种数据源,别名等设置。在利用注解配置SQL的时候,一般不需要在主配置文件中配置Mapper,个别情况下需要配置。
2,数据库表Blog:
1 2 3 4 5 6 7 8 9 | DROP TABLE IF EXISTS `blog`; CREATE TABLE `blog` ( `id` int (10) NOT NULL auto_increment, `title` varchar (200) NOT NULL , ` date ` varchar (50) NOT NULL , `authername` varchar (15) NOT NULL , `content` varchar (500) NOT NULL , PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
数据库表User:
1 2 3 4 5 6 7 8 | DROP TABLE IF EXISTS ` user `; CREATE TABLE ` user ` ( `id` int (11) NOT NULL auto_increment, `userName` varchar (50) default NULL , `userAge` int (11) default NULL , `userAddress` varchar (200) default NULL , PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
3,分别写User和Blog对应的JavaBean即setter和getter实体类。
第一种 映射器接口中写SQL语句
映射器接口注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | package com.whut.inter; import java.util.List; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; import com.whut.model.User; //最基本的注解CRUD public interface IUserDAO { @Select ( "select *from User" ) public List<User> retrieveAllUsers(); //注意这里只有一个参数,则#{}中的标识符可以任意取 @Select ( "select *from User where id=#{idss}" ) public User retrieveUserById( int id); @Select ( "select *from User where id=#{id} and userName like #{name}" ) public User retrieveUserByIdAndName( @Param ( "id" ) int id, @Param ( "name" )String names); @Insert ( "INSERT INTO user(userName,userAge,userAddress) VALUES(#{userName}," + "#{userAge},#{userAddress})" ) public void addNewUser(User user); @Delete ( "delete from user where id=#{id}" ) public void deleteUser( int id); @Update ( "update user set userName=#{userName},userAddress=#{userAddress}" + " where id=#{id}" ) public void updateUser(User user); } |
测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | package com.whut.test; import java.io.IOException; import java.io.Reader; import java.util.List; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import com.whut.inter.IUserDAO; import com.whut.model.User; public class TestUser { private static SqlSessionFactory sqlSessionFactory; private static Reader reader; static { try { Reader reader = Resources.getResourceAsReader( "mybatic-config.xml" ); sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); // 由于使用了注解,所以在主配置文件没有mapper,需要在代码里显示注册该mapper接口 sqlSessionFactory.getConfiguration().addMapper(IUserDAO. class ); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { // testSelectAll(); // testSelectByConditions(); //testAddUser(); //testDeleteUser(); testUpateUser(); } public static void testSelectAll() { // sqlSessionFactory.getConfiguration().addMapper(IUserDAO.class); SqlSession session = sqlSessionFactory.openSession(); try { IUserDAO userDAO = session.getMapper(IUserDAO. class ); List<User> users = userDAO.retrieveAllUsers(); System.out.println( "用户编号\t" + "姓名\t" + "年龄\t住址" ); for (User u : users) { System.out.println(u.getId() + "\t" + u.getUserName() + "\t" + u.getUserAge() + "\t" + u.getUserAddress()); } } finally { session.close(); } } public static void testSelectByConditions() { SqlSession session = sqlSessionFactory.openSession(); try { IUserDAO userDAO = session.getMapper(IUserDAO. class ); User u = userDAO.retrieveUserByIdAndName( 4 , "%spring%" ); if (u != null ) { System.out.println( "用户编号\t" + "姓名\t" + "年龄\t住址" ); System.out.println(u.getId() + "\t" + u.getUserName() + "\t" + u.getUserAge() + "\t" + u.getUserAddress()); } } finally { session.close(); } } public static void testAddUser() { User u = new User(); u.setUserName( "dongtian" ); u.setUserAge( 51 ); u.setUserAddress( "hubeisheng" ); SqlSession session = sqlSessionFactory.openSession(); try { IUserDAO userDAO = session.getMapper(IUserDAO. class ); userDAO.addNewUser(u); session.commit(); } finally { session.close(); } } public static void testDeleteUser() { SqlSession session = sqlSessionFactory.openSession(); try { IUserDAO userDAO = session.getMapper(IUserDAO. class ); userDAO.deleteUser( 7 ); session.commit(); } finally { session.close(); } } public static void testUpateUser() { User u = new User(); u.setId( 4 ); u.setUserName( "dongtian" ); u.setUserAge( 51 ); u.setUserAddress( "hubeisheng" ); SqlSession session = sqlSessionFactory.openSession(); try { IUserDAO userDAO = session.getMapper(IUserDAO. class ); userDAO.updateUser(u); session.commit(); } finally { session.close(); } } } |
第二种 映射器接口调用SqlBuilder生成的SQL进行执行
映射器接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | package com.whut.inter; import java.util.List; import org.apache.ibatis.annotations.CacheNamespace; import org.apache.ibatis.annotations.DeleteProvider; import org.apache.ibatis.annotations.InsertProvider; import org.apache.ibatis.annotations.Options; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Result; import org.apache.ibatis.annotations.ResultMap; import org.apache.ibatis.annotations.Results; import org.apache.ibatis.annotations.SelectProvider; import org.apache.ibatis.annotations.UpdateProvider; import org.apache.ibatis.type.JdbcType; import com.whut.model.Blog; import com.whut.sqlTool.BlogSqlProvider; @CacheNamespace (size= 100 ) public interface IBlogDAO { @SelectProvider (type = BlogSqlProvider. class , method = "getSql" ) @Results (value ={ @Result (id= true , property= "id" ,column= "id" ,javaType=Integer. class ,jdbcType=JdbcType.INTEGER), @Result (property= "title" ,column= "title" ,javaType=String. class ,jdbcType=JdbcType.VARCHAR), @Result (property= "date" ,column= "date" ,javaType=String. class ,jdbcType=JdbcType.VARCHAR), @Result (property= "authername" ,column= "authername" ,javaType=String. class ,jdbcType=JdbcType.VARCHAR), @Result (property= "content" ,column= "content" ,javaType=String. class ,jdbcType=JdbcType.VARCHAR), }) public Blog getBlog( @Param ( "id" ) int id); @SelectProvider (type = BlogSqlProvider. class , method = "getAllSql" ) @Results (value ={ @Result (id= true , property= "id" ,column= "id" ,javaType=Integer. class ,jdbcType=JdbcType.INTEGER), @Result (property= "title" ,column= "title" ,javaType=String. class ,jdbcType=JdbcType.VARCHAR), @Result (property= "date" ,column= "date" ,javaType=String. class ,jdbcType=JdbcType.VARCHAR), @Result (property= "authername" ,column= "authername" ,javaType=String. class ,jdbcType=JdbcType.VARCHAR), @Result (property= "content" ,column= "content" ,javaType=String. class ,jdbcType=JdbcType.VARCHAR), }) public List<Blog> getAllBlog(); @SelectProvider (type = BlogSqlProvider. class , method = "getSqlByTitle" ) @ResultMap (value = "sqlBlogsMap" ) //这里调用resultMap,这个是SQL配置文件中的,必须该SQL配置文件与本接口有相同的全限定名 //注意文件中的namespace路径必须是使用@resultMap的类路径 public List<Blog> getBlogByTitle( @Param ( "title" )String title); @InsertProvider (type = BlogSqlProvider. class , method = "insertSql" ) public void insertBlog(Blog blog); @UpdateProvider (type = BlogSqlProvider. class , method = "updateSql" ) public void updateBlog(Blog blog); @DeleteProvider (type = BlogSqlProvider. class , method = "deleteSql" ) @Options (useCache = true , flushCache = false , timeout = 10000 ) public void deleteBlog( int ids); } |
SQL生成器(利用SqlBuilder生成)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | package com.whut.sqlTool; import java.util.Map; import static org.apache.ibatis.jdbc.SqlBuilder.*; public class BlogSqlProvider { private final static String TABLE_NAME = "blog" ; public String getSql(Map<Integer, Object> parameter) { BEGIN(); //SELECT("id,title,authername,date,content"); SELECT( "*" ); FROM(TABLE_NAME); //注意这里这种传递参数方式,#{}与map中的key对应,而map中的key又是注解param设置的 WHERE( "id = #{id}" ); return SQL(); } public String getAllSql() { BEGIN(); SELECT( "*" ); FROM(TABLE_NAME); return SQL(); } public String getSqlByTitle(Map<String, Object> parameter) { String title = (String) parameter.get( "title" ); BEGIN(); SELECT( "*" ); FROM(TABLE_NAME); if (title != null ) WHERE( " title like #{title}" ); return SQL(); } public String insertSql() { BEGIN(); INSERT_INTO(TABLE_NAME); VALUES( "title" , "#{title}" ); // VALUES("title", "#{tt.title}"); //这里是传递一个Blog对象的,如果是利用上面tt.方式,则必须利用Param来设置别名 VALUES( "date" , "#{date}" ); VALUES( "authername" , "#{authername}" ); VALUES( "content" , "#{content}" ); return SQL(); } public String deleteSql() { BEGIN(); DELETE_FROM(TABLE_NAME); WHERE( "id = #{id}" ); return SQL(); } public String updateSql() { BEGIN(); UPDATE(TABLE_NAME); SET( "content = #{content}" ); WHERE( "id = #{id}" ); return SQL(); } } |
注意由于在映射器接口中调用了@ResultMap,该注解内容是SQL配置文件ResultMap的ID,它是允许访问SQL配置文件中的ResultMap,则需要在相应的SQL配置相应ResultMap,然后再在主配置文件加上该SQL配置的Mapper路径。并且该SQL配置文件的namespace必须与使用@ResultMap的映射器接口的全限定相同。Blog.xml如下。
1 2 3 4 5 6 7 8 9 10 11 12 | <? 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.whut.inter.IBlogDAO" > < resultMap type = "Blog" id = "sqlBlogsMap" > < id property = "id" column = "id" /> < result property = "title" column = "title" /> < result property = "authername" column = "authername" /> < result property = "date" column = "date" /> < result property = "content" column = "content" /> </ resultMap > </ mapper > |
再在主配置文件mybatis-config.xml加入一句mapper。
1 2 3 | < mappers > < mapper resource = "com/whut/model/Blog.xml" /> </ mappers > |
测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | package com.whut.test; import java.io.IOException; import java.io.Reader; import java.util.List; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import com.whut.inter.IBlogDAO; import com.whut.model.Blog; /** * 注意这里是一种利用SqlBuilder以及多种设置来注解使用 * @author zxl * */ public class TestBlog { private static SqlSessionFactory sqlSessionFactory; private static Reader reader; static { try { Reader reader = Resources.getResourceAsReader( "mybatic-config.xml" ); sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); // 由于使用了注解,所以在主配置文件没有mapper,需要在代码里显示注册该mapper接口 //sqlSessionFactory.getConfiguration().addMapper(IBlogDAO.class); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { //testOneBlog(); //testAllBlog(); //testBlogByTitle(); //testAddBlog(); //testDeleteBlog(); testUpdateBlog(); } public static void testOneBlog() { SqlSession session=sqlSessionFactory.openSession(); try { IBlogDAO dao=session.getMapper(IBlogDAO. class ); Blog blog=dao.getBlog( 2 ); System.out.println(blog.getId()+ "\t" +blog.getAuthername()+ "\t" +blog.getTitle()); } finally { session.close(); } } public static void testAllBlog() { SqlSession session=sqlSessionFactory.openSession(); try { IBlogDAO dao=session.getMapper(IBlogDAO. class ); List<Blog> blogs=dao.getAllBlog(); System.out.println( "编号\t作者\t标题" ); for (Blog blog:blogs) System.out.println(blog.getId()+ "\t" +blog.getAuthername()+ "\t" +blog.getTitle()); } finally { session.close(); } } public static void testBlogByTitle() { SqlSession session=sqlSessionFactory.openSession(); try { IBlogDAO dao=session.getMapper(IBlogDAO. class ); List<Blog> blogs=dao.getBlogByTitle( "%word%" ); System.out.println( "编号\t作者\t标题" ); for (Blog blog:blogs) System.out.println(blog.getId()+ "\t" +blog.getAuthername()+ "\t" +blog.getTitle()); } finally { session.close(); } } public static void testAddBlog() { SqlSession session=sqlSessionFactory.openSession(); Blog blog= new Blog(); blog.setTitle( "chuntian" ); blog.setAuthername( "xiaohua" ); blog.setDate( "2013/12/25" ); blog.setContent( "bushuangyayya" ); try { IBlogDAO dao=session.getMapper(IBlogDAO. class ); dao.insertBlog(blog); session.commit(); } finally { session.close(); } } public static void testDeleteBlog() { SqlSession session=sqlSessionFactory.openSession(); try { IBlogDAO dao=session.getMapper(IBlogDAO. class ); dao.deleteBlog( 5 ); session.commit(); } finally { session.close(); } } public static void testUpdateBlog() { SqlSession session=sqlSessionFactory.openSession(); Blog blog= new Blog(); blog.setId( 6 ); blog.setTitle( "daxuexiaoyuan" ); blog.setAuthername( "xiaohua" ); blog.setDate( "2013/2/25" ); blog.setContent( "冷死了" ); try { IBlogDAO dao=session.getMapper(IBlogDAO. class ); dao.updateBlog(blog); session.commit(); } finally { session.close(); } } } |
注意事项:
1) 在利用注解配置映射器接口的时候,必须要通过
sqlSessionFactory.getConfiguration().addMapper(IBlogDAO.class);来对给映射器接口注册,如果映射器接口中使用了@ResultMap注解,则由于已经在mybatis-config.xml配置了Mapper,则就不需要再次在代码中添加mapper。
2)当方法有多个参数的时候,为了与SQL语句中的#{}对应,一般可以使用@Param("")来为每个参数命别名,使得该别名与#{}对应。当参数只有一个的时候,不需要别名。
3 在进行更新删除添加的时候,如果传递的是一个实体对象,则SQL可以直接使用实体的属性。
4)映射器接口调用SqlBuilder中的方法,都是将参数转换为Map中的key,可以在SqlBuilder的方法中利用Map来获取传递的参数值,进而进行逻辑操作判断。
5)注解中对于返回多条记录的查询可以直接利用@Results和@Result来配置映射,或者利用@ResultMap来调用SQL配置文件中的ResultMap。
--------------------------------------------------------------------------------------------------------------------
(1)官方开发文档:http://ibatis.apache.org/docs/dotnet/datamapper/ch03s09.html
<isGreaterThan prepend="AND" property="bo.lastUpdatedBy" compareValue="0">
<![CDATA[(
LAST_UPDATED_BY=#bo.lastUpdatedBy:NUMERIC#
)]]>
</isGreaterThan>
在ibatis中,该属性用于判断传入的值是否大于0
<isNotNull prepend="AND" property="bo.lastUpdateDate" >
<![CDATA[(
LAST_UPDATE_DATE=#bo.lastUpdateDate:TIMESTAMP#
)]]>
</isNotNull>
在ibatis中,该属性用于判断传入的值是否为空
IBATIS动态查询语句
<!-- 在ibatis中使用安全的拼接语句,动态查询 ibatis比JDBC的优势之一,安全高效说明文字在注释中 --> <select id="selectA
<!--
在ibatis中使用安全的拼接语句,动态查询
ibatis比JDBC的优势之一,安全高效
说明文字在注释中
-->
<select id="selectAllProducts" parameterClass="Product" resultMap="ProductResult">
select id,note from Product
<dynamic prepend="WHERE">
<!-- isNotNull判断参数是否存在,Integer类型 -->
<isNotNull property="id">
<!-- isGreaterThan判断参数是否大于compareValue,isGreaterEquals是大于等于 -->
<isGreaterThan prepend=" and " property="id" compareValue="0">
id = #id#
</isGreaterThan>
</isNotNull>
<!-- isNotEmpty判断字串不为空,isEmpty可以判断字串为空 -->
<isNotEmpty prepend=" and " property="note">
<!-- 模糊查询不能用#,#在是用prepareStatement的?插入参数,$是文本替换 -->
note like '%$note$%'
</isNotEmpty>
</dynamic>
</select>
用Map传参数
<select id="selectAllProducts" parameterClass="java.util.HashMap" resultMap="ProductResult">
select id,note from Product
<dynamic prepend="WHERE">
<!-- isPropertyAvailable判断属性是否有效 -->
<isPropertyAvailable property="id">
<isNotNull property="id">
<!-- isLessThan判断参数是否小于compareValue,isLessEquals是小于等于 -->
<isLessThan prepend=" and " property="id" compareValue="10">
id = #id#
</isLessThan>
</isNotNull>
</isPropertyAvailable>
</dynamic>
</select>
<!--------------------------------------------------------------------几个常用属性-->
<isPropertyAvailable> 属性是存在
<isNotPropertyAvailable> 属性不存在
<isNull> 属性值是null
<isEmpty> 判断Collection.size<1或String.length()<1
<isEqual> 等于
<isNotEqual> 不等于
<isGreaterThan> 大于
<isGreaterEqual> 大于等于
<isLessThan> 小于
<isLessEqual> 小于等于
ibatis中使用安全的拼接语句,动态查询,大于、小于、等于2012-11-26 17:38:13| 分类: 默认分类 |举报|字号 订阅
在ibatis中使用安全的拼接语句,动态查询ibatis比JDBC的优势之一,安全高效说明文字在注释中<select id="selectAllProducts" parameterClass="Product" resultMap="ProductResult">
select id,note from Product <dynamic prepend="WHERE"> <!-- isNotNull判断参数是否存在,Integer类型 --> <isNotNull property="id"> <!-- isGreaterThan判断参数是否大于compareValue,isGreaterEquals是大于等于 --> <isGreaterThan prepend=" and " property="id" compareValue="0"> id = #id# </isGreaterThan> </isNotNull> <!-- isNotEmpty判断字串不为空,isEmpty可以判断字串为空 --> <isNotEmpty prepend=" and " property="note"> <!-- 模糊查询不能用#,#在是用prepareStatement的?插入参数,$是文本替换 --> note like '%$note$%' </isNotEmpty> </dynamic> </select>用Map传参数 <select id="selectAllProducts" parameterClass="java.util.HashMap" resultMap="ProductResult"> select id,note from Product <dynamic prepend="WHERE"> <!-- isPropertyAvailable判断属性是否有效 --> <isPropertyAvailable property="id"> <isNotNull property="id"> <!-- isLessThan判断参数是否小于compareValue,isLessEquals是小于等于 --> <isLessThan prepend=" and " property="id" compareValue="10"> id = #id# </isLessThan> </isNotNull> </isPropertyAvailable> </dynamic> </select>/*动态SQL的参数有属性关键字
含义<isEqual> 如果参数相等于值则查询条件有效。<isNotEqual> 如果参数不等于值则查询条件有效。<isGreaterThan> 如果参数大于值则查询条件有效。<isGreaterEqual> 如果参数等于值则查询条件有效。<isLessEqual> 如果参数小于值则查询条件有效。如下所示:<isLessEqual prepend = ”AND” property = ”age” compareValue = ”18” >
ADOLESCENT = ‘TRUE’
</isLessEqual>
<isPropertyAvailable> 如果参数有使用则查询条件有效。<isNotPropertyAvailable> 如果参数没有使用则查询条件有效。<isNull> 如果参数为NULL则查询条件有效。<isNotNull> 如果参数不为NULL则查询条件有效。<isEmpty> 如果参数为空则查询条件有效。<isNotEmpty> 如果参数不为空则查询条件有效。参数的数据类型为Collection、String 时参数不为NULL或“”。如下所示:<isNotEmpty prepend=”AND” property=”firstName” >
FIRST_NAME=#firstName#
</isNotEmpty>
<isParameterPresent> 如果参数类不为NULL则查询条件有效。<isNotParameterPresent> Checks to see if the parameter object is not present (null). Example Usage:<isNotParameterPresent prepend=”AND”>
EMPLOYEE_TYPE = ‘DEFAULT’
</isNotParameterPresent>
在复杂查询过程中,我们常常需要根据用户的选择决定查询条件,这里发生变化的并不只是SQL 中的参数,包括Select 语句中所包括的字段和限定条件,都可能发生变化。典型情况,如在一个复杂的组合查询页面,我们必须根据用户的选择和输入决定查询的条件组合。一个典型的页面如下:
对于这个组合查询页面,根据用户选择填写的内容,我们应为其生成不同的查询语句。如用户没有填写任何信息即提交查询请求,我们应该返回所有记录:
Select * from t_user;如用户只在页面上填写了姓名“Erica”,我们应该生成类似:Select * from t_user where name like ‘%Erica%’ ;的SQL查询语句。如用户只在页面上填写了地址“Beijing”,我们应该生成类似:Select * from t_user where address like ‘%Beijing%”;的SQL。而如果用户同时填写了姓名和地址(”Erica”&’Beijing’),则我们应生成类似:Select * from t_user where name like ‘%Erica%’ and address like ‘%Beijing%”的SQL查询语句。对于ibatis 这样需要预先指定SQL 语句的ORM 实现而言,传统的做法无非通过if-else 语句对输入参数加以判定,然后针对用户选择调用不同的statement 定义。对于上面这种简单的情况(两种查询条件的排列组合,共4 种情况)而言,statement 的重复定义工作已经让人不厌其烦,而对于动辄拥有七八个查询条件,乃至十几个查询条件
的排列组合而言,琐碎反复的statement定义实在让人不堪承受。考虑到这个问题,ibatis引入了动态映射机制,即在statement定义中,根据不同的
查询参数,设定对应的SQL语句。还是以上面的示例为例:<select id="getUsers"parameterClass="user"resultMap="get-user-result"> selectid,name,sexfrom t_user<dynamic prepend="WHERE"><isNotEmpty prepend="AND" property="name">(name like #name#)</isNotEmpty><isNotEmpty prepend="AND" property="address">(address like #address#)</isNotEmpty></dynamic></select>通过dynamic 节点,我们定义了一个动态的WHERE 子句。此WHERE 子句中将可能包含两个针对name 和address 字段的判断条件。而这两个字段是否加入检索取决于用户所提供的查询条件(字段是否为空[isNotEmpty])。对于一个典型的Web程序而言,我们通过HttpServletRequest获得表单中的字段名并将其设入查询参数,如:user.setName(request.getParameter("name"));user.setAddress(request.getParameter("address"));sqlMap.queryForList("User.getUsers", user);在执行queryForList("User.getUsers", user)时,ibatis 即根据配置文件中设定的SQL动态生成规则,创建相应的SQL语句。上面的示例中,我们通过判定节点isNotEmpty,指定了关于name 和address 属性的动态规则:<isNotEmpty prepend="AND" property="name">(name like #name#)</isNotEmpty>这个节点对应的语义是,如果参数类的"name"属性非空(isNotEmpty,即非空字符串””),则在生成的SQL Where字句中包括判定条件(name like #name#),其中#name#将以参数类的name属性值填充。Address属性的判定生成与name属性完全相同,这里就不再赘述。这样,我们通过在statement 定义中引入dynamic 节点,很简单的实现了SQL 判定子句的动态生成,对于复杂的组合查询而言,这将带来极大的便利。判定节点的定义可以非常灵活,我们甚至可以使用嵌套的判定节点来实现复杂的动态映射,如:<isNotEmpty prepend="AND" property="name">( name=#name#<isNotEmpty prepend="AND" property="address">address=#address#</isNotEmpty>)</isNotEmpty>这段定义规定,只有用户提供了姓名信息时,才能结合地址数据进行查询(如果只提供地址数据,而将姓名信息忽略,将依然被视为全检索)。Dynamic节点和判定节点中的prepend属性,指明了本节点中定义的SQL子句在主体SQL中出现时的前缀。如:<dynamic prepend="WHERE">
<isNotEmpty prepend="AND" property="name">(name like #name#)</isNotEmpty><isNotEmpty prepend="AND" property="address">(address like #address#)</isNotEmpty></dynamic>假设"name"属性的值为“Erica”, "address"属性的值为“Beijing”,则会生成类似下面的SQL子句(实际运行期将生成带占位符的PreparedStatement,之后再为其填充数据):
WHERE (name like ‘Beijing’) AND (address like ‘Beijing’)
其中WHERE 之后的语句是在dynamic 节点中所定义,因此以dynamic 节点的prepend设置("WHERE")作为前缀,而其中的”AND”,实际上是address属性所对应的isNotEmpty节点的prepend设定,它引领了对应节点中定义的SQL子句。至于name属性对应的isNotEmpty节点,由于ibatis会自动判定是否需要追加prepend前缀,这里(name like #name#)是WHERE 子句中的第一个条件子句,无需AND 前缀,所以自动省略。
判定节点并非仅限于isNotEmpty,ibatis中提供了丰富的判定定义功能。判定节点分两类:
? 一元判定
一元判定是针对属性值本身的判定,如属性是否为NULL,是否为空值等。上面示例中isNotEmpty就是典型的一元判定。一元判定节点有:
节点名 描述
<isPropertyAvailable> 参数类中是否提供了此属性<isNotPropertyAvailable> 与<isPropertyAvailable>相反<isNull> 属性值是否为NULL<isNotNull> 与<isNull>相反<isEmpty> 如果属性为Collection或者String,其size是否<1,如果非以上两种类型,则通过String.valueOf(属性值)获得其String类型的值后,判断其size是否<1<isNotEmpty> 与<isEmpty>相反。? 二元判定
二元判定有两个判定参数,一是属性名,而是判定值,如<isGreaterThan prepend="AND" property="age"compareValue="18">(age=#age#)</isGreaterThan>其中,property="age"指定了属性名”age”,compareValue=”18”指明了判定值为”18”。上面判定节点isGreaterThan 对应的语义是:如果age 属性大于18(compareValue),则在SQL中加入(age=#age#)条件。二元判定节点有:节点名 属性值与compareValues的关系<isEqual> 相等。<isNotEqual> 不等。<isGreaterThan> 大于<isGreaterEqual> 大于等于<isLessThan> 小于<isLessEqual> 小于等于为了防止SQL注入,iBatis模糊查询时也要避免使用$$来进行传值。下面是三个不同数据库的ibatis的模糊查询传值。 mysql: select * from stu where name like concat('%',#name #,'%') oracle: select * from stu where name like '%'||#name #||'%' SQL Server:select * from stu where name like '%'+#name #+'% 如:<!-- 用途:小二后台查询活动的数目 --> <!-- 频率:1000/天 --> <!-- 维护:刘飞 --> <select id="countActivitySearch" resultClass="java.lang.Long" parameterClass="actDO"> <![CDATA[ select count(id) from activity ]]> <dynamic prepend="WHERE"> <isNotNull prepend=" AND " property="name"> name LIKE CONCAT('%', #name#, '%') </isNotNull> <isNotNull prepend=" AND " property="itemId"> itemId = #itemId# </isNotNull> <isNotNull prepend=" AND " property="itemName"> itemName LIKE CONCAT('%', #itemName#, '%') </isNotNull> <isNotNull prepend=" AND " property="status"> status = #status# </isNotNull> <isNotNull prepend=" AND " property="actStatus"> actStatus = #actStatus# </isNotNull> <isNotNull prepend=" AND " property="domain"> domain LIKE CONCAT('%', #domain#, '%') </isNotNull> </dynamic> </select> <!-- 用途:小二后台查询活动的列表 --> <!-- 频率:1000/天 --> <!-- 维护:刘飞 --> <select id="searchActivityForList" resultMap="actResult" parameterClass="actDO"> <![CDATA[ select * from activity ]]> <dynamic prepend="WHERE"> <isNotNull prepend=" AND " property="name"> name LIKE CONCAT('%', #name#, '%') </isNotNull> <isNotNull prepend=" AND " property="itemId"> itemId = #itemId# </isNotNull> <isNotNull prepend=" AND " property="itemName"> itemName LIKE CONCAT('%', #itemName#, '%') </isNotNull> <isNotNull prepend=" AND " property="status"> status = #status# </isNotNull> <isNotNull prepend=" AND " property="actStatus"> actStatus = #actStatus# </isNotNull> <isNotNull prepend=" AND " property="domain"> domain LIKE CONCAT('%', #domain#, '%') </isNotNull> </dynamic> <![CDATA[ order by starttime desc, createtime desc limit #startRow#, #perPageSize# ]]> </select>
IBatis模糊查詢
<!--
在ibatis中使用安全的拼接语句,动态查询ibatis比JDBC的优势之一,安全高效说明文字在注释中--> <select id="selectAllProducts" parameterClass="Product" resultMap="ProductResult"> select id,note from Product <dynamic prepend="WHERE"> <!-- isNotNull判断参数是否存在,Integer类型 --> <isNotNull property="id"> <!-- isGreaterThan判断参数是否大于compareValue,isGreaterEquals是大于等于 --> <isGreaterThan prepend=" and " property="id" compareValue="0"> id = #id# </isGreaterThan> </isNotNull> <!-- isNotEmpty判断字串不为空,isEmpty可以判断字串为空 --> <isNotEmpty prepend=" and " property="note"> <!-- 模糊查询不能用#,#在是用prepareStatement的?插入参数,$是文本替换 --> note like '%$note$%' </isNotEmpty> </dynamic> </select>用Map传参数 <select id="selectAllProducts" parameterClass="java.util.HashMap" resultMap="ProductResult"> select id,note from Product <dynamic prepend="WHERE"> <!-- isPropertyAvailable判断属性是否有效 --> <isPropertyAvailable property="id"> <isNotNull property="id"> <!-- isLessThan判断参数是否小于compareValue,isLessEquals是小于等于 --> <isLessThan prepend=" and " property="id" compareValue="10"> id = #id# </isLessThan> </isNotNull> </isPropertyAvailable> </dynamic> </select> <!--------------------------------------------------------------------几个常用属性--><isPropertyAvailable> 属性是存在
<isNotPropertyAvailable> 属性不存在<isNull> 属性值是null<isEmpty> 判断Collection.size<1或String.length()<1<isEqual> 等于<isNotEqual> 不等于<isGreaterThan> 大于<isGreaterEqual> 大于等于<isLessThan> 小于<isLessEqual>---------------------
Ibatis的动态查询使得数据操作变得非常的灵活,下次举出了常用的动态查询的属性信息:
Ibatis配置信息- <!-- Dynamic Sql -->
- <typeAlias alias="Student" type="com.ibatis.Student" />
- <typeAlias alias="StudentDTO" type="com.ibatis.StudentDTO" />
- <select id="dynamicGetStudent" parameterClass="StudentDTO"
- resultClass="Student">
- select *
- from student
- <dynamic prepend="WHERE">
- <isNotEqual prepend="AND" property="sid" compareValue="0">
- sid = #sid#
- </isNotEqual>
- <isNotNull prepend="AND" property="sname">
- sname = #sname#
- </isNotNull>
- </dynamic>
- <dynamic prepend="order by">
- <isParameterPresent>
- <isEqual prepend="order by" property="sort" compareValue="1">
- sname desc,socre
- </isEqual>
- <isEqual prepend="order by" property="sort" compareValue="2">
- sname asc,socre
- </isEqual>
- </isParameterPresent>
- </dynamic>
- </select>
Student的信息
- package com.ibatis;
- import java.util.Date;
- public class Student {
- private int sid;
- private String sname;
- private String major;
- private Date birth;
- private int socre;
- public int getSid() {
- return sid;
- }
- public void setSid(int sid) {
- this.sid = sid;
- }
- public String getSname() {
- return sname;
- }
- public void setSname(String sname) {
- this.sname = sname;
- }
- public String getMajor() {
- return major;
- }
- public void setMajor(String major) {
- this.major = major;
- }
- public Date getBirth() {
- return birth;
- }
- public void setBirth(Date birth) {
- this.birth = birth;
- }
- public int getSocre() {
- return socre;
- }
- public void setSocre(int socre) {
- this.socre = socre;
- }
- @Override
- public String toString() {
- String content = "Sid="+this.sid+"\t"+"Sname="+this.sname+"\t"+this.birth.toLocaleString();
- return content;
- }
- }
StudentDTO的信息
- package com.ibatis;
- import java.util.Date;
- public class StudentDTO {
- private int sid;
- private String sname;
- private String major;
- private Date birth;
- private int socre;
- private int sort;
- public int getSort() {
- return sort;
- }
- public void setSort(int sort) {
- this.sort = sort;
- }
- public int getSid() {
- return sid;
- }
- public void setSid(int sid) {
- this.sid = sid;
- }
- public String getSname() {
- return sname;
- }
- public void setSname(String sname) {
- this.sname = sname;
- }
- public String getMajor() {
- return major;
- }
- public void setMajor(String major) {
- this.major = major;
- }
- public Date getBirth() {
- return birth;
- }
- public void setBirth(Date birth) {
- this.birth = birth;
- }
- public int getSocre() {
- return socre;
- }
- public void setSocre(int socre) {
- this.socre = socre;
- }
- @Override
- public String toString() {
- String content = "Sid="+this.sid+"\t"+"Sname="+this.sname+"\t"+this.birth.toLocaleString();
- return content;
- }
- }
Java中的调用信息
- @SuppressWarnings("unchecked")
- public static void main(String[] args) {
- List<Student> list = dao.dynamicGetStudent(studentDTO);
- for(Student student : list){
- System.out.println("name:"+student.getSname());
- }
- System.out.println("size:"+list.size());
- }
- @Override
- public List dynamicGetStudent(StudentDTO studentDTO) {
- List result = null;
- try {
- result = sqlMapClient.queryForList("dynamicGetStudent",studentDTO);
- } catch (SQLException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return result;
- }
动态查询中的常用属性:
属性关键字 | 含义 |
<isEqual> | 如果参数相等于值则查询条件有效 |
<isNotEqual> | 如果参数不等于值则查询条件有效 |
<isGreaterThan> | 如果参数大于值则查询条件有效 |
<isGreaterEqual> | 如果参数等于值则查询条件有效 |
<isLessEqual> | 如果参数小于值则查询条件有效。如下所示:<isLessEqual prepend = ”AND” property = ”age” compareValue = ”18” >ADOLESCENT = ‘TRUE’</isLessEqual> |
<isPropertyAvailable> | 如果参数有使用则查询条件有效。 |
<isNotPropertyAvailable> | 如果参数没有使用则查询条件有效 |
<isNull> | 如果参数为NULL则查询条件有效 |
<isNotNull> | 如果参数不为NULL则查询条件有效 |
<isEmpty> | 如果参数为空则查询条件有效 |
<isNotEmpty> | 如果参数不为空则查询条件有效 |
<isParameterPresent> | 如果参数类不为NULL则查询条件有效 |
<isNotParameterPresent> | Checks to see if the parameter object is not present (null). Example Usage |