学习MyBatis的第一天

MyBatis简述

MyBatis是Apache的一个开源项目IBatis,是一个基于Java的持久层框架,支持普通sql查询,存储过程和高级映射,MyBatis开源使用简单的xml或注解用于配置和原始映射,将接口和Java的POJO映射成数据库中的记录。
MyBatis:更加简化jdbc代码,简单持久层sql语句从代码中分离,利用反射,将表中数据与java bean属性——映射即ORM(Object Relational Mapping对象关系映射)
使用范围:
对于需求不固定的项目,建议使用Mybaits,因为可以灵活编写sql语句。
特点:
mybaits学习门槛比hibernate低;灵活性高,特别适用于业务模型易变的项目,使用范围广。

一、MyBatis功能架构

1.API接口层:提供给外部使用的接口API,开发人员通过这些本地 API 来操纵 数据库。接口层接收到调用请求就会调用数据处理层来完成具体的数据处理。
2.数据处理层:负责具体SQL查找、SQL解析、SQL执行和执行结果映射处理等。主要目的是根据调用的请求完成一次数据库操作。
3.基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,为上层的数据处理层提供最基础的支撑。

二、MyBatis配置文件解释

1.properties
这些属性都是可外部配置且可动态替换的,既可以在典型的 Java 属性文件中配 置,亦可通过 properties 元素的子元素来传递。例如:

<property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis" /> <property name="username" value="root" /> <property name="password" value="root" />

其中的属性就可以在整个配置文件中使用来替换需要动态配置的属性值。比如:

 <property name="driver" value="${driver}"/> 
 <property name="url" value="${url}"/>
 <property name="username" value="${username}"/>
 <property name="password" value="${password}"/>

如何配?
在 config.xml 文件中引入子标签

<properties resource="jdbc.properties"></properties>

并修改原有数据源连接相关配置如下:

<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" /> <property name="password" value="${password}" /> </dataSource> </environment> </environments>

2.setting
这是 MyBatis 修改操作运行过程细节的重要的步骤。下方这个表格描述了这些设 置项、含义和默认值。一般我们用默认即可(详细解释见官网文档)

在这里插入图片描述
对应 xml 配置如下(开发中一般采用默认配置即可):

<settings>
 <setting name="cacheEnabled" value="true"/> 
 <setting name="lazyLoadingEnabled" value="true"/>
 <setting name="multipleResultSetsEnabled" value="true"/>  <setting name="useColumnLabel" value="true"/> 
 <setting name="useGeneratedKeys" value="false"/>
 <setting name="autoMappingBehavior" value="PARTIAL"/> 
 <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
 <setting name="defaultExecutorType" value="SIMPLE"/> 
 <setting name="defaultStatementTimeout" value="25"/> 
 <setting name="defaultFetchSize" value="100"/>
 <setting name="safeRowBoundsEnabled" value="false"/>   
 <setting name="mapUnderscoreToCamelCase" value="false"/>  	
 <setting name="localCacheScope" value="SESSION"/> 
 <setting name="jdbcTypeForNull" value="OTHER"/>
 <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
  </settings>

3.typeAliases
类型别名是为 Java 类型设置一个短的名字。它只和 XML 配置有关,存在的意义 仅在于用来减少类完全限定名的冗余。
Configuration 标签下添加

<typeAliases> <typeAlias alias="User" type="com.shsxt.mybatis.po.User" /> </typeAliases>

修改 UserMapper.xml 文件

<mapper namespace="com.shsxt.mybatis.mapper.UserMapper">
	<select id="queryUserById" parameterType="int " resultType="User"> 
		select id,userName,userPwd from user where id=#{id} 	
	</select> 
</mapper>

也可以指定一个包名(大家最喜欢的方式),MyBatis 会在包名下面搜索需要的 Java Bean,比如:

<typeAliases> 
<!-- <typeAlias alias="User" type="com.shsxt.mybatis.po.User" /> -->
	<package name="com.shsxt.mybatis.po"/>
 </typeAliases>

每一个在包 com.shsxt.mybatis.po 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 com.shsxt.mybatis.po.User 的别名为 user;
若有注解,则别名为其注解值。 注解名@Alias(value=“user”)

4.typeHandlers 类型处理器
无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是 从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。
你可以重写类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型。 具体做法为:实现 org.apache.ibatis.type.TypeHandler 接口, 或继承 一个很便利的类 org.apache.ibatis.type.BaseTypeHandler, 然后可以 选择性地将它映射到一个 JDBC 类型。

  1. 对象工厂(objectFactory)
    MyBatis每次创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成。默认的对象工厂需要做的仅仅是实例化目标类,要么提供默认构造方法来实例化。默认清空下,我们不需要配置,mybaits会调用默认实现的objectFactory。从这个累的外部看,这个类的主要主要就是根据一个类的类型得到该类的一个实体对象,比如,我们给他一个user的type,他将会给我们一个Tiger的实体对象,我们给他一个java.lang.List对象,他将会给我们一个List的实体对象,类似于spring工厂实例化bean

6.plugins插件
MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下, MyBatis 允许使用插件来拦截的方法调用包括:

  • Executor (sql 执 行 时 , update, query, flushStatements, commit,
    rollback, getTransaction, close, isClosed)
  • ParameterHandler (参数的处理, getParameterObject, setParameters)
  • ResultSetHandler (结果集的处理, handleResultSets, handleOutputParameters)
  • StatementHandler (申明语句的处理, prepare, parameterize, batch, update,
    query)

这些类中方法的细节可以通过查看每个方法的签名来发现,或者直接查看 MyBatis 的发行包中的源代码。 假设你想做的不仅仅是监控方法的调用,那么你应该很好的了 解正在重写的方法的行为。 因为如果在试图修改或重写已有方法的行为的时候,你很 可能在破坏 MyBatis 的核心模块。 这些都是更低层的类和方法,所以使用插件的时候 要特别当心。
通过 MyBatis 提供的强大机制,使用插件是非常简单的,只需实现 Interceptor 接口,并指定了想要拦截的方法签名即可。

总配置添加

<!-- 插件 -->
 <plugins> 
 	<plugin interceptor="com.shsxt.plugins.ExamplePlugin">
		<property name="hello" value="100" />
	</plugin> 
</plugins>

7.配置环境(environments)
MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种 数据库之中, 现实情况下有多种理由需要这么做。例如,开发、测试和生产 环境需要有不同的配置;或者共享相同 Schema 的多个生产数据库, 想使用 相同的 SQL 映射。许多类似的用例。
不过要记住:尽管可以配置多个环境,每个 SqlSessionFactory 实例只能选 择其一。
所以,如果你想连接两个数据库,就需要创建两个 SqlSessionFactory 实 例,每个数据库对应一个。而如果是三个数据库,就需要三个实例,依此类 推。

  • 每个数据库对应一个 SqlSessionFactory 实例
<environments default="development"> 
	<environment id="development"> 
		<transactionManager type="JDBC" />
		<dataSource type="POOLED"> 
			<property name="driver" value="${driver}" /> 
			<property name="url" value="${url}" />
			<property name="password" value="${password}" /> 
		</dataSource> 
	</environment> 
	<environment id="test">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
			   <property name="driver" value="${driver2}" /> 	
			   <property name="url" value="${url2}" /> 
			   	<property name="username" value="${username2}" /> 
			   	<property name="password" value="${password2}" /> 	
			</dataSource> 
	 </environment> 
 </environments>

db.properties配置文件中有两个数据库配置

## development driver=com.mysql.jdbc.Driver 
url=jdbc:mysql://127.0.0.1:3306/mybatis?
useUnicode=true&amp;characterEncodi ng=utf8 username=root 
password=root ## test driver2=com.mysql.jdbc.Driver 
url2=jdbc:mysql://127.0.0.1:3306/mybatis2?
useUnicode=true&amp;characterEnco ding=utf8 
username2=root password2=root

测试 sqlSessionFactory

public void test02() {
 InputStream in;
  try {
  		in = Resources. 				
  			getResourceAsStream(this.getClass().getClassLoader(), "config.xml"); 
		 // 默认开发库
		 //SqlSessionFactory sqlSessionFactory= new SqlSessionFactoryBuilder().build(in); 
		 // 测试库
		   SqlSessionFactory sqlSessionFactory= new
		   SqlSessionFactoryBuilder().build(in,"test"); 
		   UserDao userDao=new UserDaoImpl(sqlSessionFactory); 
		   User user= userDao.queryUserById(1); 
		   System.out.println(user); 
			   } catch (IOException e) { 
			 	  e.printStackTrace();
			   } 
		}

8.事务管理器(transactionManager)
在 MyBatis 中有两种类型的事务管理器(也就 type=”[JDBC|MANAGED]”):

  • JDBC – 这个配置就是直接使用了 JDBC 的提交和回滚设置,它依赖于 从数据源得到的连接来管理事务范围。
  • MANAGED – 这个配置几乎没做什么。它从来不提交或回滚一个连接, 而是让容器来管理事务的整个生命周期。 默认情况下它会关闭连接,然而 一些容器并不希望这样,因此需要将 closeConnection 属性设置为 false 来 阻止它默认的关闭行为。例如:
<transactionManager type="MANAGED">
	 <property name="closeConnection" value="false"/> 
 </transactionManager>

如果你在使用Spring+MyBatis,则没有必要配置事务管理器,因为Spring模块会使用自带的管理器来覆盖前面的配置。

9.dataSource数据源
dataSouce元素使用标准的JDBC数据源接口来配置JDBC连接对象的主要。
数据源类型三种:UNPOOLED,POOLED,JNDI
UNPOOLED
这个数据源的实现只是每次被请求时打开和关闭连接。虽然有一点慢,它对在及时可用连接方面没有性能要求的绝对有用程序是一个很好的选择。不同的数据库在这方面表现不一样的,使用对某些数据库来说使用连接池并不重要,这个配置也是理想的。

-driver ——这是JDBC驱动的Java类的完全限定名(并不是JDBC驱动中可能包含的数据源类)

-url——这是数据库的JDBC URL地址。

-username——登录数据库的用户名

-password——登录数据库的密码

-defaultTransactionlsolationLevel ——默认的连接事务隔离级别。

-driver.encoding=UTF-8

POOLED
这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连 接实例时所必需的初始化和认证时间。 这是一种使得并发 Web 应用快速响应请求的 流行处理方式。(一般选用这种)

  • poolMaximumActiveConnections – 在任意时间可以存在的活动(也就是正 在使用)连接数量,默认值:10
  • poolMaximumIdleConnections – 任意时间可能存在的空闲连接数。
  • poolMaximumCheckoutTime – 在 被 强 制 返 回 之 前 , 池 中 连 接 被 检 出 (checked out)时间,默认值:20000 毫秒(即 20 秒)
  • poolTimeToWait – 这是一个底层设置,如果获取连接花费的相当长的时间,它会给连接池打印状态日志并重新尝试获取一个连接(避免在误配置的情 况下一直安静的失败),默认值:20000 毫秒(即 20 秒)。
  • poolPingQuery–发送到数据库的侦测查询,用来检验连接是否处在正常工作秩序中并准备接受请求。默认是“NOPINGQUERYSET”,这会导致多数数 据库驱动失败时带有一个恰当的错误消息。
  • poolPingEnabled–是否启用侦测查询。若开启,也必须使用一个可执行的SQL语句设置poolPingQuery属性(最好是一个非常快的SQL),默认 值:false。
  • poolPingConnectionsNotUsedFor–配置poolPingQuery的使用频度。这可以被设置成匹配具体的数据库连接超时时间,来避免不必要的侦测,默认 值:0(即所有连接每一时刻都被侦测—当然仅当poolPingEnabled为true时适用)。

JNDI
这个数据源的实现是为了能在如EJB或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个JNDI上下文的引用。

  • initial_context–这个属性用来在InitialContext中寻找上下文(即,initialContext.lookup(initial_context))。这是个可选属性,如果忽略,那么data_source属性将会直接从InitialContext中寻找。
  • data_source–这是引用数据源实例位置的上下文的路径。提供了initial_context配置时会在其返回的上下文中进行查找,没有提供时则直接在InitialContext中查找。

和其他数据源配置类似,可以通过添加前缀“env.”直接把属性传递给初始上下文。比

  • env.encoding=UTF8
    这就会在初始上下文(InitialContext)实例化时往它的构造方法传递值为UTF8的encoding属性。

10.mappers 映射器(四种配置)
这里是告诉mybatis去哪寻找映射SQL的语句。可以使用类路径中的资源引用,或者使用字符,输入确切的URL引用。
在这里插入图片描述
这些配置会告诉了MyBatis去哪里找映射文件,剩下的细节就应该是每个SQL映射文件。

三、封装Dao

新建接口UserDao 以及对应实现类UserDaoImpl
接口定义:

publicinterfaceUserDao{
	publicUserqueryUserById(intid);
}

实现类:

publicclassUserDaoImplimplementsUserDao{
		/**
		*到整合spring时直接注入即可
		*/
	private SqlSessionFactory factory;
	public UserDaoImpl(){
	}
	
	publicUserDaoImpl(SqlSessionFactoryfactory){
		this.factory=factory;
	}
	
	public User queryUserById(int id){
		Useruser=null;
		SqlSessionsession=null;
		try{
			//打开session
			session=factory.openSession();
			/**
			*调用selectOne查询方法返回单条记录多条记录会报错!
			*参数1:UserMapper.xml中对应的statementid同时加上命名空间
			*参数2:输入参数*/
			user=session.selectOne("com.shsxt.mybatis.mapper.UserMapper.queryUserById",id);
			}catch(Exceptione){
				e.printStackTrace();
			}finally{
				if(null!=session){
			session.close();
			}
		}		
		return user;
	}
}

四、Mapper Xml映射文件

MyBatis的真正强大在于它的映射语句,也是它的魔力所在。由于它的异常强大,映射器的XML文件就显得相对简单。如果拿它跟具有相同功能的JDBC代码进 行对比,你会立即发现省掉了将近95%的代码。MyBatis就是针对SQL构建的,并 且比普通的方法做的更好。
SQL映射文件有很少的几个顶级元素(按照它们应该被定义的顺序):

  • cache–给定命名空间的缓存配置。
  • cache-ref–其他命名空间缓存配置的引用。
  • resultMap–是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。
  • parameterMap–已废弃!老式风格的参数映射。内联参数是首选,这个元素可能在将来被移除,这里不会记录。
  • sql–可被其他语句引用的可重用语句块。
  • insert–映射插入语句
  • update–映射更新语句
  • delete–映射删除语句
  • select–映射查询语句
    查询语句是MyBatis中最常用的元素之一(映射文件配置见代码)
    1.Select元素标签使用
    输入参数分类
    基本类型,字符串,javabean,map,数组(删除操作时体现),List(添加时体 现)等每种情况定义如下
    基本数据类型:输入
  • Statement
<!--输入参数为基本数据类型-->
<selectid="queryUserById"parameterType="int" resultType="user">
	selectid,user_nameasuserName,user_pwdasuserPwdfromuserwhereid=#{id}
</select>

Dao方法定义与对应实现

  @Override
    public User queryUserById(Integer id){
        SqlSession session = build.openSession();
        UserMapper userMapper = session.getMapper(UserMapper.class);
        User user = userMapper.queryUserById(id);
        session.close();
        return user;
    }
  • 字符串类型
    Statement定义
<!--每条结果类型为实体最终结果为多条记录list结果-->
<selectid="queryUserByName"parameterType="string"resultType="user">
	selectid,user_nameasuserName,user_pwd as userPwd from user where user_name like concat("%",#{userName},"%")
</select>
	

Dao方法定义与对应实现

 @Override
    public User queryUserByName(String userName) {
        SqlSession session = build.openSession();
        UserMapper userMapper = session.getMapper(UserMapper.class);
        User user = userMapper.queryUserByName(userName);
        session.close();
        return user;
    }
  • Map类型
    Statement定义
<!--输入参数为map类型-->
<selectid="queryUserByMap"parameterType="map"resultType="user">
	selectid,user_nameasuserName,user_pwdasuserPwdfromuserwhereid=#{id}
</select>

Dao方法定义与对应实现

 public User queryUserByMap(Map map) {
        SqlSession session = build.openSession();
        UserMapper userMapper = session.getMapper(UserMapper.class);
        User user = userMapper.queryUserByMap(map);
        session.close();
        return user;
    }

Java Bean、Map
Statement定义

 <!-- Java Bean -->
    <select id="queryUserByUser" parameterType="user"  resultType="user">
        select id,user_name as userName,user_pwd as userPwd from user where user_name=#{userName}
    </select>
    <!-- Map -->
    <select id="queryUserByMap" parameterType="map"  resultType="user">
        select id,user_name as userName,user_pwd as userPwd from user where user_name=#{userName}
    </select>

Dao方法定义与对应实现

  @Override
    public User queryUserByUser(User user) {
        SqlSession session = build.openSession();
        UserMapper userMapper = session.getMapper(UserMapper.class);
        User user2 = userMapper.queryUserByUser(user);
        session.close();
        return user2;
    }

    @Override
    public User queryUserByMap(Map map) {
        SqlSession session = build.openSession();
        UserMapper userMapper = session.getMapper(UserMapper.class);
        User user = userMapper.queryUserByMap(map);
        session.close();
        return user;
    }

输出
Statement定义

  <!-- 输出类型 -->
    <!-- int -->
    <select id="queryUserTotal" resultType="int">
        SELECT count(*) FROM user
    </select>
    <!-- String -->
    <select id="queryUserNameById" resultType="string">
        SELECT user_name FROM user WHERE id=#{id}
    </select>
    <!-- Map -->
    <select id="queryUserMapById" resultType="map">
        SELECT * FROM user WHERE id=#{id}
    </select>
    <!-- List -->
    <select id="queryUserList" resultType="user">
        SELECT * FROM user
    </select>


Dao方法定义与对应实现

 @Override
    public Integer queryUserTotal() {
        SqlSession session = build.openSession();
        UserMapper userMapper = session.getMapper(UserMapper.class);
        Integer total = userMapper.queryUserTotal();
        session.close();
        return total;
    }

    @Override
    public String queryUserNameById(Integer id) {
        SqlSession session = build.openSession();
        UserMapper userMapper = session.getMapper(UserMapper.class);
        String userName = userMapper.queryUserNameById(id);
        session.close();
        return userName;
    }

    @Override
    public Map queryUserMapById(Integer id) {
        SqlSession session = build.openSession();
        UserMapper userMapper = session.getMapper(UserMapper.class);
        Map map = userMapper.queryUserMapById(id);
        session.close();
        return map;
    }

    @Override
    public List<User> queryUserList() {
        SqlSession session = build.openSession();
        UserMapper userMapper = session.getMapper(UserMapper.class);
        List<User> userList = userMapper.queryUserList();
        session.close();
        return userList;
    }
}

2.Insert元素标签使用(四种添加配置篇幅限制,方法实现见课堂代码!)
添加记录不返回主键配置

<insert id="addUserNoKey" parameterType="user">
        INSERT INTO user (
            user_name,
            user_pwd
        )
        VALUES
            (
                #{userName},
                #{userPwd}
            )
    </insert>

添加记录返回主键1(属性配置)

<insert id="addUserHasKey" parameterType="user">
        <selectKey keyProperty="id" order="AFTER" resultType="int">
            select LAST_INSERT_ID() as id
        </selectKey>
        INSERT INTO user (
            user_name,
            user_pwd
        )
        VALUES
            (
                #{userName},
                #{userPwd}
            )
    </insert>

添加记录返回主键2(属性配置)

INSERT INTO user (
user_name,
user_pwd
)
VALUES
(
#{userName},
#{userPwd}
)

批量添加记录返回影响总记录行数(属性配置)

 <insert id="addUserBatch" parameterType="list">
        INSERT INTO user (
            user_name,
            user_pwd
        )
        VALUES
        <foreach collection="list" item="item" separator=",">
            (
            #{item.userName},
            #{item.userPwd}
            )
        </foreach>

    </insert>

3.Update元素标签使用
更新单条记录返回影响行数

 <update id="updateUser" parameterType="user">
        UPDATE user set user_name=#{userName}, user_pwd=#{userPwd} where id=#{id}
    </update>

批量更新多条记录属性配置

 <update id="updateUserBatch">
        UPDATE user set user_pwd='123456' where id in (
        <foreach collection="array" item="item" separator=",">
            #{item}
        </foreach>
        )
    </update>

4.Delete元素标签使用
删除单条记录

 <delete id="delUserById" parameterType="int">
        delete from user where id=#{id}
    </delete>

批量删除多条记录(属性配置)

 <delete id="deleteUserBatch" >
        delete from user where id in
        <foreach collection="array" item="item" open="(" separator="," close=")">
            #{item}
        </foreach>
    </delete>

五、动态sql语句

I.基于xml配置
MyBatis的强大特性之一便是它的动态SQL。如果你有使用JDBC或其他类似框架的经验,你就能体会到根据不同条件拼接SQL语句有多么痛苦。拼接的时候要确 保不能忘了必要的空格,还要注意省掉列名列表最后的逗号。利用动态SQL这一特性可以彻底摆脱这种痛苦。它借助ognl(类似于jsp 里面的el表达式)表达式来完成动态sql的拼接使得非常简便。
1.if条件判断
动态SQL通常要做的事情是有条件地包含where子句的一部分。比如:

 <!-- 模糊匹配 -->
    <select id="queryUserByUserName" parameterType="user" resultType="user">
        select id,user_name as userName,user_pwd as userPwd from user where 1=1
        <if test="@Ognl@isNotEmpty(userName)">
            and user_name like concat('%',#{userName},'%')
        </if>
    </select>

使用if标签就是加一个test属性作为判断,如果有多个条件组合判断的话用and,or 连接
实现方法

@Override
publicList<User>queryUserByUserName(StringuserName){
	List<User>users=null;
	SqlSessionsession=null;
	try{	
		session=sqlSessionFactory.openSession();
		Mapmap=newHashMap();//map参数
		map.put("userName",userName);
		users=session.selectList("com.shsxt.mapper.UserMapper.queryUserByUserName",map);
		
	}catch(Exceptione){
		e.printStackTrace();
	}finally{
		if(null!=session){
			session.close();
		}
	}
	return users;
}

2.choose,when,otherwise选择器使用
我们不想用到所有的条件语句,而只想从中择其一二。针对这种情况,MyBatis提供了choose元素,它有点像Java中的switch语句

   <!-- choose -->
    <select id="queryUserByNation" parameterType="user" resultType="user">
        SELECT id,
        <choose>
            <when test="null!=nation and ''!=nation">
                user_name as userName
            </when>
            <otherwise>
                real_name as realName
            </otherwise>
        </choose>
        from user
    </select>

实现

 @Test
    public void queryUserByNation() {
        User user = new User();
        user.setNation("china");
        List<User> userList = userMapper.queryUserByNation(user);
        userList.stream().forEach(System.out::println);
    }

3.trim,where,set

  <select id="queryUserList2" parameterType="user" resultType="user">
        select id,user_name as userName,user_pwd as userPwd from user
        <where>
            <if test="null!=userName and ''!=userName">
                and user_name like concat('%',#{userName},'%')
            </if>
            <if test="null!=userPwd and ''!=userPwd">
                and user_pwd like concat('%',#{userPwd},'%')
            </if>
        </where>
    </select>

    <select id="queryUserList3" parameterType="user" resultType="user">
        select id,user_name as userName,user_pwd as userPwd from user
        <trim prefix="where" prefixOverrides="and">
            <if test="null!=userName and ''!=userName">
                and user_name like concat('%',#{userName},'%')
            </if>
            <if test="null!=userPwd and ''!=userPwd">
                and user_pwd like concat('%',#{userPwd},'%')
            </if>
        </trim>
    </select>

实现

 @Test
    public void queryUserList2() {
        User user = new User();
        user.setUserName("test");
//        user.setUserPwd("88");
        List<User> userList = userMapper.queryUserList2(user);
//        userList.stream().forEach(System.out::println);
    }
    @Test
    public void queryUserList3() {
        User user = new User();
        user.setUserName("test");
        user.setUserPwd("88");
        List<User> userList = userMapper.queryUserList3(user);
//        userList.stream().forEach(System.out::println);
    }


4.foreach
动态SQL的另外一个常用的必要操作是需要对一个集合进行遍历,通常是在构建IN 条件语句或者是批量插入。比如:

<selectid="findUserByUserName"resultMap="RM_User">
	select userId,userName,password  from user
	<where>
		<if test="userNameList != null">
			userNamein
			<foreach	item="item" index="index" collection="userNameList" open="("separator=","close=")">
			#{item}
			</foreach>
		</if>
	</where>
</select>

使用Ognl表达式
我们在上面的映射中,如果用if去判断一个值是否为空或者是空字符串时我们是这样 做的test="userName!=nullanduserName!=’’"这样写起来比较复杂,为此我们采 用Ognl表达式@Ognl@isNotEmpty(userName)去判断。
使用ognl表达式时我们要在根目录的包下面加上Ognl的一个Java类,这里面会有各种各样的判断比如为空判断@Ognl@isEmpty(userName),不为空判断。
@Ognl@isNotEmpty(userName),是否是空字符串@Ognl@isBlank(userName),不为空字 符串@Ognl@isNotBlank(userName)等等


/**
 * Ognl工具类,主要是为了在ognl表达式访问静态方法时可以减少长长的类名称编写
 * Ognl访问静态方法的表达式为: @class@method(args)
 * 
 * 示例使用: 
 * <pre>
 *  &lt;if test="@Ognl@isNotEmpty(userId)">
 *      and user_id = #{userId}
 *  &lt;/if>
 * </pre>
*
 */
public class Ognl {
    
    /**
     * 可以用于判断String,Map,Collection,Array是否为空
     * @param o
     * @return
     */
    @SuppressWarnings("rawtypes")
    public static boolean isEmpty(Object o) throws IllegalArgumentException {
        if(o == null) return true;

        if(o instanceof String) {
            if(((String)o).length() == 0){
                return true;
            }
        } else if(o instanceof Collection) {
            if(((Collection)o).isEmpty()){
                return true;
            }
        } else if(o.getClass().isArray()) {
            if(Array.getLength(o) == 0){
                return true;
            }
        } else if(o instanceof Map) {
            if(((Map)o).isEmpty()){
                return true;
            }
        }else {
            return false;
//          throw new IllegalArgumentException("Illegal argument type,must be : Map,Collection,Array,String. but was:"+o.getClass());
        }

        return false;
    }
    
    /**
     * 可以用于判断 Map,Collection,String,Array是否不为空
     * @param c
     * @return
     */ 
    public static boolean isNotEmpty(Object o) {
        return !isEmpty(o);
    }
    
    public static boolean isNotBlank(Object o) {
        return !isBlank(o);
    }
    
    public static boolean isBlank(Object o) {
        if(o == null)
            return true;
        if(o instanceof String) {
            String str = (String)o;
            return isBlank(str);
        }
        return false;
    }

    public static boolean isBlank(String str) {
        if(str == null || str.length() == 0) {
            return true;
        }
        
        for (int i = 0; i < str.length(); i++) {
            if (!Character.isWhitespace(str.charAt(i))) {
                return false;
            }
        }
        return true;
    }

}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值