大目录
1、Mybatis缓存
2、Mybatis逆向工程
3、输入映射和输出映射
a) 输入参数映射
b) 返回值映射
c) resultMap
4、动态sql
a) If
b) Where
c) Foreach
5、关联查询
a) 一对一关联
b) 一对多关联
c) 多对多关联
1、Mybatis简单配置介绍,基于XML的配置
(1)配置步骤
简单来说,Mybatis的配置主要分为以下几步(整合Spring之后有些就不需要了,但是一开始学习不建议直接整合Spring):
- 编写POJO即JavaBean,最终的目的是将数据库中的查询结果映射到JavaBean上;
- 配置与POJO对应的Mapper接口:里面有各种方法,对应mapper.xml中的查询语句;
- 配置与POJO对应的XML映射:编写缓存,SQL查询等;
- 配置mybatis-config.xml主要的Mybatis配置文件:配置数据源、扫描mapper.xml等。
注意:以上的配置并没有严格的前后顺序;
2、Mybatis生命周期
mybatis-config.xml
------->SqlSessionFactoryBuilder(创建一个构建器,一旦创建了SqlSessionFactory,它的任务就算完成了,可以回收)
-------->SqlSessionFacotry 相当于JDBC的一个Connection对象,每次应用程序需要访问数据库,我们就要通过SqlSessionFactory创建一个SqlSession
-------->SqlSession 请求数据库处理事务的过程中
-------->mapper;是一个接口,发送SQL 或返回结果,存活于一个SqlSession内
备注:
- 所以SqlSessionFactory在整Mybatis整个生命周期中(每个数据库对应一个SqlSessionFactory,是单例产生的)
- SqlSession是一个线程不安全的对象(在多线程的情况下,需要特别注意),即存活于一个应用的请求和申请,可以执行多条SQL保证事务的一致性。
- 当SqlSession销毁的时候,Mapper也会销毁。
3、Myabtis缓存介绍
将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。
mybatis提供查询缓存,用于减轻数据压力,提高数据库性能。
mybaits提供一级缓存,和二级缓存。
(1)系统缓存:包括一级缓存与二级缓存
一级缓存:默认情况下Myabtis对于同一个SqlSession开启一级缓存
- 在默认 只会开启一级缓存(只针对同一个SqlSession而言);
- 在参数与SQL完全一样的情况下并且不声明刷新缓存没超时的,使用同一个SqlSession对象调用同一个Mapper方法时(SqlSession对象生命周期为方法级别),SqlSession只会取出当前缓存数据,不会再到数据库中进行查询,从而提高查询效率;
- 不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。
运作的时候:
第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户信息。
得到用户信息,将用户信息存储到一级缓存中。
如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。
二级缓存:这里可以结合SqlSessionFactory等的生命周期能加深理解
运作的时候:
首先开启mybatis的二级缓存。
sqlSession1去查询用户id为1的用户信息,查询到用户信息会将查询数据存储到二级缓存中。
sqlSession2去查询用户id为1的用户信息,去缓存中找是否存在数据,如果存在直接从缓存中取出数据。
如果SqlSession3去执行相同 mapper下sql,执行commit提交,清空该 mapper下的二级缓存区域的数据。
二级缓存与一级缓存区别,二级缓存的范围更大,多个sqlSession可以共享一个UserMapper的二级缓存区域。数据类型仍然为HashMap
UserMapper有一个二级缓存区域(按namespace分,如果namespace相同则使用同一个相同的二级缓存区),其它mapper也有自己的二级缓存区域(按namespace分)。
每一个namespace的mapper都有一个二缓存区域,两个mapper的namespace如果相同,这两个mapper执行sql查询到数据将存在相同的二级缓存区域中。
-
不同的SqlSession是隔离的,为了解决这个问题,我们可以在SqlSessionFactory层面上设置二级缓存提供各个对象SqlSession
-
二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession去操作数据库得到数据会存在二级缓存区域,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
-
二级缓存是多个SqlSession共享的,其作用域是mapper的同一个namespace,不同的sqlSession两次执行相同namespace下的sql语句且向sql中传递参数也相同即最终执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。
-
Mybatis默认没有开启二级缓存需要在setting全局参数中配置开启二级缓存。如果缓存中有数据就不用从数据库中获取,大大提高系统性能。
-
二级缓存默认是不开启的,需要进行配置,Mybatis要求返回的POJO必须是可序列化的,即POJO实现Serializable接口。
缓存的配置只需要在XML配置< cache/>即可,或者指定算法,刷新时间间隔,缓存状态,大小等
< cache eviction=“LRU” readOnly=“true” flushInterval=“100000” size=“1024”>< /cache>
A. 映射语句文件中所有select语句将会被缓存;
B. 映射语句文件中所有insert、update和delete语句会被刷新缓存;
C. 缓存使用默认的LRU最近最少使用算法回收;
D. 根据时间表,缓存不会任何时间顺序刷新;
E. 缓存会存储列表集合或对象的1024个引用
F. 缓存被视为可read/write的缓存,意味着是不可以被共享的,而可以被安全地修改。
(2)自定义缓存:结合Redis等主流缓存配置
我们可以使用比如现在比较火的Redis缓存,需要实现Myabtis为我们提供的接口org.apache.ibatis.cache.Cache。虽然现在主流Mybatis用的都是自定义缓存,
开启二级缓存
mybaits的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,还要在具体的mapper.xml中开启二级缓存
1)在核心配置文件SqlMapConfig.xml中加入
<setting name="cacheEnabled" value="true"/>
2)在UserMapper.xml中开启二缓存,UserMapper.xml下的sql执行完成会存储到它的缓存区域(HashMap)。
cn.atcast.mapper/UserMapper.xml
3) mybatis二级缓存需要将查询结果映射的pojo实现 java.io.serializable接口,如果不实现则抛出异常:
org.apache.ibatis.cache.CacheException: Error serializing object. Cause: java.io.NotSerializableException: cn.itcast.mybatis.po.User
二级缓存可以将内存的数据写到磁盘,存在对象的序列化和反序列化,所以要实现java.io.serializable接口。
如果结果映射的pojo中还包括了pojo,都要实现java.io.serializable接口。
二级缓存禁用
对于变化频率较高的sql,需要禁用二级缓存:
在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存。(对一些重要的数据比如说财务数据是一定不能再缓存中的)
<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">
刷新缓存
如果sqlsession操作commit操作(更新删除等操作),对二级缓存进行刷新(全局清空)。(局限性)
设置statement的flushCache是否刷新缓存,默认值是true。
二级缓存的应用场景
对查询频率高,变化频率低的数据建议使用二级缓存。
对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访问速度,业务场景比如:耗时较高的统计分析sql、电话账单查询sql等。
实现方法如下:通过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushInterval,比如设置为30分钟、60分钟、24小时等,根据需求而定。
Mybatis缓存的局限性
mybatis二级缓存对细粒度的数据级别的缓存实现不好,比如如下需求:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品信息,此时如果使用mybatis的二级缓存就无法实现当一个商品变化时只刷新该商品的缓存信息而不刷新其它商品的信息,因为mybaits的二级缓存区域以mapper为单位划分,当一个商品信息变化会将所有商品信息的缓存数据全部清空。解决此类问题需要在业务层根据需求对数据有针对性缓存。
mybatis的cache参数(了解)
mybatis的cache参数只适用于mybatis维护缓存。
flushInterval(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段。
默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。
size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的可用内存资源数目。
默认值是1024。
readOnly(只读)属性可以被设置为true或false。只读的缓存会给所有调用者返回缓存对象的相同实例。
因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false。
如下例子:
< cache eviction=“FIFO” flushInterval=“60000” size=“512” readOnly=“true”/>
这个更高级的配置创建了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会导致冲突。可用的收回策略有, 默认的是 LRU:
- LRU – 最近最少使用的:移除最长时间不被使用的对象。
- FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
Mybatis实现分布式缓存
Mybatis逆向工程
在generatorConfig.xml中配置mapper生成的详细信息,注意改下几点:
1、 添加要生成的数据库表
2、 po文件所在包路径
3、 mapper文件所在包路径
6.1 第一步:mapper生成配置文件:
在generatorConfig.xml中配置mapper生成的详细信息,注意改下几点:
1、 添加要生成的数据库表
2、 po文件所在包路径
3、 mapper文件所在包路径
配置文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="caigouTables" targetRuntime="MyBatis3">
<commentGenerator>
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis" userId="root" password="root">
</jdbcConnection>
<!--
<jdbcConnection driverClass="oracle.jdbc.OracleDriver"
connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:orcl"
userId="scott"
password="tiger">
</jdbcConnection>
-->
<!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer true,把JDBC DECIMAL 和
NUMERIC 类型解析为java.math.BigDecimal -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- targetProject:生成PO类的位置 -->
<javaModelGenerator targetPackage="cn.atcast.pojo"
targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
<!-- 从数据库返回的值被清理前后的空格 -->
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- targetPackage:mapper映射文件生成的位置 -->
<sqlMapGenerator targetPackage="cn.atcast.mapper"
targetProject=".\src">
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- targetPackage:mapper接口的生成位置 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="cn.atcast.mapper"
targetProject=".\src">
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- 指定表 -->
<table schema="" tableName="user" />
<table schema="" tableName="orders" />
</context>
</generatorConfiguration>
6.2 第二步:使用java类生成mapper文件:
GeneratorSqlmap.java
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.exception.XMLParserException;
import org.mybatis.generator.internal.DefaultShellCallback;
public class GeneratorSqlmap {
public void generator() throws Exception{
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("generatorConfig-base.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,
callback, warnings);
myBatisGenerator.generate(null);
}
public static void main(String[] args) throws Exception {
try {
GeneratorSqlmap generatorSqlmap = new GeneratorSqlmap();
generatorSqlmap.generator();
} catch (Exception e) {
e.printStackTrace();
}
}
}
6.3 第三步:拷贝生成的mapper文件到工程中指定目录中
6.3.1 Mapper.xml
Mapper.xml的文件拷贝至mapper目录内
6.3.2 Mapper.java
Mapper.java的文件拷贝至mapper 目录内
注意:mapper xml文件和mapper.java文件在一个目录内且文件名相同。
6.4 第四步Mapper接口测试
学会使用mapper自动生成的增、删、改、查方法。
cn.atcast.mapper/UserMapper.java
package cn.atcast.test;
import java.io.InputStream;
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 org.junit.Before;
import org.junit.Test;
import cn.atcast.mapper.UserMapper;
import cn.atcast.pojo.User;
public class UserMapperTest {
private SqlSessionFactory factory;
// 作用:在测试方法前执行这个方法
@Before
public void setUp() throws Exception {
String resource = "SqlMapConfig.xml";
// 通过流将核心配置文件读取进来
InputStream inputStream = Resources.getResourceAsStream(resource);
// 通过核心配置文件输入流来创建会话工厂
factory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testFindUserById() throws Exception {
SqlSession openSession = factory.openSession();
UserMapper mapper = openSession.getMapper(UserMapper.class);
User user=mapper.selectByPrimaryKey(1);
System.out.println(user);
}
}
6.5 逆向工程注意事项
6.5.1 Mapper文件内容不覆盖而是追加
XXXMapper.xml文件已经存在时,如果进行重新生成则mapper.xml文件内容不被覆盖而是进行内容追加,结果导致mybatis解析失败。
解决方法:删除原来已经生成的mapper xml文件再进行生成。
Mybatis自动生成的po及mapper.java文件不是内容而是直接覆盖没有此问题。
7 Hibernate与Mybatis对比
首先简单介绍下两者的概念
Hibernate :Hibernate 是当前最流行的ORM框架,对数据库结构提供了较为完整的封装。
Mybatis:Mybatis同样也是非常流行的ORM框架,主要着力点在于POJO 与SQL之间的映射关系。
其次具体从几个方面说一下两者的区别:
1.两者最大的区别
针对简单逻辑,Hibernate和MyBatis都有相应的代码生成工具,可以生成简单基本的DAO层方法。
针对高级查询,Mybatis需要手动编写SQL语句,以及ResultMap。而Hibernate有良好的映射机制,开发者无需关心SQL的生成与结果映射,可以更专注于业务流程。
2.开发难度对比
Hibernate的开发难度要大于Mybatis。主要由于Hibernate比较复杂、庞大,学习周期较长。
而Mybatis则相对简单一些,并且Mybatis主要依赖于sql的书写,让开发者感觉更熟悉。
3.sql书写比较
Mybatis的SQL是手动编写的,所以可以按需求指定查询的字段。不过没有自己的日志统计,所以要借助log4j来记录日志。
Hibernate也可以自己写SQL来指定需要查询的字段,但这样就破坏了Hibernate开发的简洁性。不过Hibernate具有自己的日志统计。
4.数据库扩展性比较
Mybatis由于所有SQL都是依赖数据库书写的,所以扩展性,迁移性比较差。
Hibernate与数据库具体的关联都在XML中,所以HQL对具体是用什么数据库并不是很关心。
5.缓存机制比较
相同点:Hibernate和Mybatis的二级缓存除了采用系统默认的缓存机制外,都可以通过实现你自己的缓存或为其他第三方缓存方案,创建适配器来完全覆盖缓存行为。
不同点:Hibernate的二级缓存配置在SessionFactory生成的配置文件中进行详细配置,然后再在具体的表-对象映射中配置是那种缓存。
MyBatis的二级缓存配置都是在每个具体的表-对象映射中进行详细配置,这样针对不同的表可以自定义不同的缓存机制。并且Mybatis可以在命名空间中共享相同的缓存配置和实例,通过Cache-ref来实现。
两者比较:因为Hibernate对查询对象有着良好的管理机制,用户无需关心SQL。所以在使用二级缓存时如果出现脏数据,系统会报出错误并提示。
而MyBatis在这一方面,使用二级缓存时需要特别小心。如果不能完全确定数据更新操作的波及范围,避免Cache的盲目使用。否则,脏数据的出现会给系统的正常运行带来很大的隐患。
6.总结
Hibernate与MyBatis都可以是通过SessionFactoryBuider由XML配置文件生成SessionFactory,然后由SessionFactory 生成Session,最后由Session来开启执行事务和SQL语句。
而MyBatis的优势是MyBatis可以进行更为细致的SQL优化,可以减少查询字段,并且容易掌握。
Hibernate的优势是DAO层开发比MyBatis简单,Mybatis需要维护SQL和结果映射。数据库移植性很好,MyBatis的数据库移植性不好,不同的数据库需要写不同SQL。有更好的二级缓存机制,可以使用第三方缓存。MyBatis本身提供的缓存机制不佳。
输入映射和输出映射
Mapper.xml映射文件中定义了操作数据库的sql,每个sql是一个statement,映射文件是mybatis的核心。
2.1 parameterType(输入类型)
2.1.1 传递简单类型
cn.atcast.mapper/UserMapper.xml
<select id="findUserById" parameterType="int" resultType="cn.atcast.pojo.User">
select * from user where id=#{id}
</select>
2.1.2 传递pojo对象
Mybatis使用ognl表达式(对象导航图 )解析对象字段的值,#{}或者${}括号中的值为pojo属性名称。
cn.atcast.mapper/UserMapper.xml
<insert id="insertUser" parameterType="cn.atcast.pojo.User" >
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
select LAST_INSERT_ID()
</selectKey>
insert into user (username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
</insert>
2.1.3 传递pojo包装对象
开发中通过pojo传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。
需求:根据用户名查询用户信息,查询条件放到QueryVo的user属性中。
2.1.3.1 QueryVo
cn.atcast.pojo/QueryVo.java
package cn.atcast.pojo;
public class QueryVo {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
2.1.3.2 Sql语句
>SELECT * FROM user where username like '%王%'
2.1.3.3 接口
>cn.atcast.mapper/UserMapper.java
public List< User> findUserbyVo(QueryVo vo);
2.1.3.4 Mapper文件
>cn.atcast.mapper/UserMapper.xml
>< select id="findUserbyVo" parameterType="cn.atcast.pojo.QueryVo" resultType="cn.atcast.pojo.User">
select * from user where username like '%${user.username}%' and sex=#{user.sex}
< /select>
2.1.3.5 测试方法
@Test
public void testFindUserByVo() throws Exception{
SqlSession openSession = factory.openSession();
//通过getMapper方法来实例化接口
UserMapper mapper = openSession.getMapper(UserMapper.class);
QueryVo vo = new QueryVo();
User user = new User();
user.setUsername("王");
user.setSex("1");
vo.setUser(user);
List<User> list = mapper.findUserbyVo(vo);
System.out.println(list);
}
2.2 resultType(输出类型)
2.2.1 输出简单类型
统计用户表记录数
cn.atcast.mapper/UserMapper.java
public Integer findUserCount();
cn.atcast.mapper/UserMapper.xml
<!-- 只有返回结果为一行一列的时候,那么返回值类型才可以指定成基本类型 -->
<select id="findUserCount" resultType="java.lang.Integer">
select count(*) from user
</select>
测试:
cn.atcast.test/UserMapperTest.java
@Test
public void testFindUserCount() throws Exception{
SqlSession openSession = factory.openSession();
//通过getMapper方法来实例化接口
UserMapper mapper = openSession.getMapper(UserMapper.class);
Integer count = mapper.findUserCount();
System.out.println("=====" + count);
}
输出简单类型必须查询出来的结果集有一条记录,最终将第一个字段的值转换为输出类型。
使用session的selectOne可查询单条记录。
2.3 resultMap 和resultType区分
resultType可以指定pojo将查询结果映射为pojo,但需要pojo的属性名和sql查询的列名一致方可映射成功。
如果sql查询字段名和pojo的属性名 不一致 ,可以通过resultMap将字段名和属性名作一个对应关系 ,resultMap实质上还需要将查询结果映射到pojo对象中。
- resultMap可以实现将查询结果映射为复杂类型的pojo,比如在查询结果映射对象中包括pojo和list实现一对一查询和一对多查询。
2.3.1 定义resultMap
<resultMap type="cn.atcast.pojo.Orders" id="orderAndUserResultMap">
<!-- id标签指定主键字段对应关系
column:列,数据库中的字段名称
property:属性,java中pojo中的属性名称
-->
<id column="id" property="id"/>
<!-- result:标签指定非主键字段的对应关系 -->
<result column="user_id" property="userId"/>
<result column="number" property="number"/>
<result column="createtime" property="createtime"/>
<result column="note" property="note"/>
</resultMap>
<id />:此属性表示查询结果集的唯一标识,非常重要。如果是多个字段为复合唯一约束则定义多个<id />。
Property:表示User类的属性。
Column:表示sql查询出来的字段名。
Column和property放在一块儿表示将sql查询出来的字段映射到指定的pojo类属性上。
<result />:普通结果,即pojo的属性。
3 动态sql(常用)
通过mybatis提供的各种标签方法实现动态拼接sql。
3.1 Where
------------------------------
cn.atcast.mapper/UserMapper.java
//添加这个方法
public List<User> findUserByUserNameAndSex(User user);
------------------------------
cn.atcast.mapper/UserMapper.xml
<!-- 封装sql条件,封装后可以重用.
id:是这个sql条件的唯一标识 -->
<sql id="user_Where">
<!-- where标签作用:
会自动向sql语句中添加where关键字
并且会去掉第一个条件的and关键字
-->
<where>
<if test="username != null and username != '' ">
and username like '%${username}%'
</if>
<if test="sex != null and sex != ''">
and sex=#{sex}
</if>
</where>
</sql>
<!-- 查询用户列表,根据用户名和用户性别查询用户列表 -->
<select id="findUserByUserNameAndSex" parameterType="cn.atcast.pojo.User" resultType="cn.atcast.pojo.User">
select * from user
<!-- 调用sql条件 -->
<include refid="user_Where"></include>
</select>
------------------------------
cn.atcast.test/UserMapperTest.java
@Test
public void testFindUserbyUserNameAndSex() throws Exception{
SqlSession openSession = factory.openSession();
//通过getMapper方法来实例化接口
UserMapper mapper = openSession.getMapper(UserMapper.class);
User user = new User();
user.setUsername("王");
user.setSex("1");
List<User> list = mapper.findUserByUserNameAndSex(user);
System.out.println(list);
}
------------------------------
src/SqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="db.properties"></properties>
<typeAliases>
<!-- 单个别名定义 -->
<typeAlias alias="user" type="cn.atcast.pojo.User" />
<!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) -->
<package name="cn.atcast.pojo" />
</typeAliases>
<!-- 配置数据库连接池,将db.properties中的数据库的相关信息给数据库链接池类C3P0 -->
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource> <!-- POOLED类 -->
</environment>
<environment id="oracle">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource> <!-- POOLED类 -->
</environment>
</environments>
<!-- <mappers>
<mapper class="cn.atcast.mapper.UserMapper" />
</mappers> -->
<mappers>
<package name="cn.atcast.mapper"/>
</mappers>
</configuration>
3.2 foreach
向sql传递数组或List,mybatis使用foreach解析,如下:
需求
批量删除
传入多个id查询用户信息,用下边两个sql实现:
SELECT * FROM USERS WHERE username LIKE ‘%张%’ AND (id =10 OR id =89 OR id=16)
SELECT * FROM USERS WHERE username LIKE ‘%张%’ AND id IN (10,89,16)
在pojo中定义list属性ids存储多个用户id,并添加getter/setter方法
--------------
cn.atcast.pojo/QueryVo.java
private List<Integer> ids;
public List<Integer> getIds() {
return ids;
}
public void setIds(List<Integer> ids) {
this.ids = ids;
}
--------------
cn.atcast.mapper/UserMapper.java
public List<User> findUserByIds(QueryVo vo);
-------
cn.atcast.mapper/UserMapper.xml
<select id="findUserByIds" parameterType="cn.atcast.pojo.QueryVo" resultType="cn.atcast.pojo.User">
select * from user
<where>
<if test="ids != null">
<!--
foreach:循环传入的集合参数
collection:传入的集合的变量名称
item:每次循环将循环出的数据放入这个变量中
open:循环开始拼接的字符串
close:循环结束拼接的字符串
separator:循环中拼接的分隔符
-->
<foreach collection="ids" item="id" open="id in (" close=")" separator=",">
#{id}
<!-- id IN (10,89,16) -->
</foreach>
</if>
</where>
</select>
---完整版cn.atcast.mapper/UserMapper.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">
<!-- namespace:命名空间,做sql隔离 -->
<mapper namespace="cn.atcast.mapper.UserMapper">
<select id="findUserById" parameterType="java.lang.Integer"
resultType="user">
select * from user
where id=#{id}
</select>
<!-- 模糊查询 -->
<select id="findUserByUserName" parameterType="java.lang.String"
resultType="user">
select * from user
where username like '%${value}%'
</select>
<insert id="insertUser" parameterType="cn.atcast.pojo.User">
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
select
LAST_INSERT_ID()
</selectKey>
insert into user (username,birthday,sex,address)
values(#{username},#{birthday},#{sex},#{address})
</insert>
<!-- id是uuid -->
<!-- <insert id="insertUser" parameterType="cn.atcast.pojo.User"> <selectKey
keyProperty="id" resultType="java.lang.String" order="BEFORE"> select uuid()
</selectKey> insert into user(id,username,birthday,sex,address) values(#{id},#{username},#{birthday},#{sex},#{address})
</insert> -->
<delete id="deleteUerById" parameterType="int">
delete from user where id=#{id}
</delete>
<update id="updateUserById" parameterType="cn.atcast.pojo.User">
update user
set username=#{username}
where id=#{id}
</update>
<select id="findUserbyVO" parameterType="cn.atcast.pojo.QueryVO" resultType="cn.atcast.pojo.User">
select *
from user
where username
like '%${user.username}%'
and
sex=#{user.sex}
</select>
<select id="findUserCount" resultType="java.lang.Integer">
select count(*)
from user
</select>
<!-- select * from t_user
where 1=1
and username like '%${username}%'
and sex=?-->
<sql id="user_where">
<where>
<if test="username!=null and username!=''">
and username like '%${username}%'
</if>
<if test="sex!=null and sex!=''">
and sex=#{sex}
</if>
</where>
</sql>
<select id="findUserNameAndSex" parameterType="cn.atcast.pojo.User" resultType="cn.atcast.pojo.User">
select *
from user
<include refid="user_where"></include>
</select>
<select id="findUserByIds" parameterType="cn.atcast.pojo.QueryVO" resultType="cn.atcast.pojo.User">
select *
from user
<where>
<if test="ids!=null">
<foreach collection="ids" item="id" open="id in(" close=")" separator=",">
#{id}
</foreach>
</if>
</where>
</select>
</mapper>
-------------
cn.atcast.test/UserMapperTest.java
@Test
public void testFindUserbyIds() throws Exception{
SqlSession openSession = factory.openSession();
//通过getMapper方法来实例化接口
UserMapper mapper = openSession.getMapper(UserMapper.class);
QueryVo vo = new QueryVo();
List<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(16);
ids.add(22);
vo.setIds(ids);
List<User> list = mapper.findUserByIds(vo);
System.out.println(list);
}
--------
public interface UserMapper {
public User findUserById(Integer id);
public List<User> findUserByUserName(String userName);
public void insertUser(User user);
public List<User> findUserbyVO(QueryVO vo);
public Integer findUserCount();
public List<User> findUserNameAndSex(User user);
public List<User> findUserByIds(QueryVO vo);
}
----
public class QueryVO {
private User user;
private List<Integer> ids;
public List<Integer> getIds() {
return ids;
}
public void setIds(List<Integer> ids) {
this.ids = ids;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}