讲之前,先把实体类给写出来
public class User implements Serializable {private Integer id;private String username;private Date birthday;private String sex;private String address;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", birthday=" + birthday +", sex='" + sex + '\'' +", address='" + address + '\'' +'}';}
}
1.if标签
我们根据实体类的不同取值,使用不同的sql语句来查询,例如可以根据id来查询,根据name来查询,也可以同时根据id和name来查询。
下面就来演示如何查询
首先创建接口
//复杂条件查询
public List<User> findByUser(User user);
然后对映射文件进行配置
<select id="findByUser" resultType="user" parameterType="user">
select * from user where 1=1
<if test="username!=null and username != ''">
and username=#{username}
</if>
<if test="birthday!=null">
and birthday=#{birthday}
</if>
<if test="sex!=null">
and sex=#{sex}
</if>
<if test="address!=null">
and address=#{address}
</if></select>
这里就用上了if标签,这个if就相当于java中的if判断,只要if标签中的条件成立,就会将改字段拼接到前面的select* from user where 1=1的后面。很容易理解,就是只要符合if标签中的条件就可以把if标签内的语句拼接到前面的语句的后面。
但是你有没有注意这里的where后面加了个1=1是不是有点奇怪,但其实他是为了使拼接的sql语句语法正确,不然第一个正确的if标签内的语句拼接上去后where and就会出现语法错误,所以加了个1=1,反正它又不会影响其他的判断。
测试方法
public class TestUser {
UserDao userDao;
SqlSession sqlSession;
//抽取重复的代码
@Before //这个@Before注解修饰的方法会在@Test修饰的方法之前执行
public void before() throws Exception{
//加载配置文件
InputStream in =
Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactoryBuilder
SqlSessionFactoryBuilder builder = new
SqlSessionFactoryBuilder();
//创建SqlSessionFactory对象
SqlSessionFactory sessionFactory = builder.build(in); //创建SqlSession对象 sqlSession = sessionFactory.openSession(true); //生成代理对象 userDao = sqlSession.getMapper(UserDao.class); } @After //@After注解修饰的方法在@Test注解修饰的方法之后执行 public void after(){ sqlSession.close(); } @Test public void testFindByUser(){ User user = new User(); user.setSex("男"); user.setAddress("上海"); List<User> userList = userDao.findByUser(user); for(User u : userList){ System.out.println(u); } }}
这里的@Before注解就是使被它标记的方法在@test标记的方法之前的方法执行。
@After注解就是使被它标记的方法在@test标记的方法之后的方法执行。
这么做的原因就是当有多个sql语句要执行时,不用每一次都创建相关的对象,然后再关闭。就相当于把这一段代码给提取了出来。
2.where标签
为了简化上面的where 1=1,我们可以用where标签来简化。
<select id="findByUser" resultType="user" parameterType="user"> select * from user <where> <if test="username!=null and username != ''"> and username=#{username} </if> <if test="birthday!=null"> and birthday=#{birthday} </if> <if test="sex!=null"> and sex=#{sex} </if> <if test="address!=null"> and address=#{address} </if> </where>
</select>
这里进行sql拼接的时候会自动把第一个满足条件的if标签中的语句的and给自动去掉。
3.set标签
set标签可以用来实现动态修改
接口
// 动态修改
public void updateUser(User user);
映射文件配置
<update id="updateByUser" parameterType="user">
update user
<set>
<if test="username!=null and username != '' ">
username=#{username},
</if>
<if test="birthday!=null">
birthday=#{birthday},
</if>
<if test="sex!=null and sex != '' ">
sex=#{sex},
</if>
<if test="address!=null and address != '' ">
address=#{address},
</if>
</set>
where id=#{id}</update>
还是一样的,就是满足if标签中满足条件的语句拼接上去,别忘了后面还有一个后缀,就是where id=#{id}.
测试
@Testpublic void testUpdateByUser(){ User user = new User(); user.setId(60); user.setBirthday(new Date()); user.setAddress("加拿大"); userDao.updateByUser(user);}
4.添加
定义接口
public void addUser(User user);
映射文件配置
<sql id="key"> <trim suffixOverrides=","> <if test="username!=null and username != '' "> username, </if> <if test="birthday!=null and username != '' "> birthday, </if> <if test="sex!=null and username != '' "> sex, </if> <if test="address!=null and username != '' "> address, </if> </trim></sql><sql id="value"> <trim suffixOverrides=","> <if test="username!=null and username != '' "> #{username}, </if> <if test="birthday!=null and username != '' "> #{birthday}, </if> <if test="sex!=null and username != '' "> #{sex}, </if> <if test="address!=null and username != '' "> #{address}, </if> </trim>
</sql><insert id="addUser" parameterType="user">
insert into user(<include refid="key"/>) values(<include refid="value"/>)</insert>
这里就相当于把两个sql中满足条件的语句插入insert标签中,这里又几点要说明。
首先sql中的id的取值随便去什么,只要保证它的唯一性就行了,与后面insert标签中的refid相对应就行了
然后这里的trim标签是用来对sql语句进行灵活拼接的,suffixOverrides=","就是用来删除拼接后的sql语句末尾的逗号的。
测试
@Testpublic void testAddUser(){
User user = new User();
user.setUsername("张卫健");
user.setAddress("香港");
userDao.addUser(user);}
5.choose when otherwise标签
定义接口
//根据复杂条件查询
public List<User> findByCondition(User user);
映射文件配置
<select id="findByCondition" parameterType="user"
resultType="user">
select * from user <where> <choose> <when test="username!=null and username != ''"> username=#{username} </when> <when test="birthday!=null and birthday != ''"> birthday=#{birthday} </when><when test="sex!=null and sex != ''"> sex=#{sex} </when> <when test="address!=null and address != ''"> address=#{address} </when> <otherwise> id = #{id} </otherwise></choose> </where>
</select>
这里的when otherwise就相当于if else语句,与前面的if标签不同,它这里只要满足一个条件就会中断,不像if中所有条件都要判断。
这里的otherwise就相当于else
测试
@Testpublic void test12() throws Exception{ User user = new User(); user.setUsername("ONeal"); user.setSex("男"); user.setAddress("美国"); List<User> userList = userDao.findByCondition(user); userList.forEach(u ->{ System.out.println(u); });}
6.foreach标签
当我们要根据id同时查询多个记录时,就是要输多个id来查询多个记录时,就需要用到foreach来进行操作。
有两种方式进行操作
第一种:将批量id封装到数组中
定义接口
//批量删除 将批量id封装到数组里面
public void deleteUserByIds(@Param("ids")Integer[] ids);
@Param("ids")为 Integer[] ids
这个参数指定了别名 ids
。这样在对应的 SQL 映射文件里,就可以使用 ids
来引用这个参数数组
映射文件配置
<delete id="deleteUserByIds">
delete from user where id in
(
<foreach collection="ids" item="id" separator=",">
#{id}
</foreach>
)</delete>
这里要注意的一点是,这里的sql语句是删除操作,所以用的标签是delete,如果你是要执行查询的操作,那么就是使用select标签
这里的collection就是用来接收封装id的集合的
item用来指定每次从集合中迭代取出的元素的别名,其实就只要保证item的值和#{}中的值一样就够了
separator是用来对迭代取出来的数字进行分格的,这里的separator=","意思就是用逗号将迭代取出来的数字进行分格
测试
@Testpublic void test12() throws Exception{
Integer[] ids = {1,2,3,4,5};
userDao.deleteUserByIds(ids);}
可以来看一下运行台中sql的形式的样子
我们也可以不用加@Param注解,可以
<delete id="deleteUserByIds">
delete from user where id in
(
<foreach collection="array" item="id" separator=",">
#{id}
</foreach>
)</delete>
直接指定为数组类型也是可以的,也就是说这里固定要填array。
第二种:将批量id封装到list集合中
定义接口
//批量删除 将批量id封装到List集合里面
public void deleteUserByIds(List<Integer> ids);
映射文件配置
<delete id="deleteUserByIds" parameterType="int">
delete from user where id in
(
<foreach collection="list" item="id" separator=",">
#{id}
</foreach>
)</delete>
这里的collection只能写list,其他的和前面一样的理解。
测试
@Testpublic void test12() throws Exception{
List<Integer> ids = new ArrayList<>();
ids.add(1);
ids.add(2);
ids.add(3);
ids.add(4);
ids.add(5);
userDao.deleteUserByIds(ids);}
看一下控制台中被拼接的sql语句
总结: 当我们传递一个 List 实例或者数组作为参数对象传给 MyBatis。当你这么做的时 候,MyBatis 会自动将它包装在一个 Map 中,用名称在作为键。List 实例将会以“list” 作为键,而数组实例将会以“array”作为键。所以,当我们传递的是一个List集合时, mybatis会自动把我们的list集合包装成以list为Key值的map
7.批处理
从名字就可以看出来就是批量处理一堆数据的
它有两种方式进行实现。下面以一个需求来演示
需求:批量增加数据
第一种:将批量新增的数据 放在List集合里面,遍历集合循环新增数据即可。
@Testpublic void test13() throws Exception{
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<User> userList = new ArrayList<User>();
User user1 = new User();
user1.setUsername("测试数据3");
user1.setBirthday(new Date());
user1.setSex("男");
user1.setAddress("测试数据3");
User user2 = new User();
user2.setUsername("测试数据4");
user2.setBirthday(new Date());
user2.setSex("男");
user2.setAddress("测试数据4");
userList.add(user1);
userList.add(user2);
//批量新增 for(User user : userList){
userDao.addUser(user);
}
sqlSession.commit();
}
看一下控制台执行结果
这里sql语句执行了多次,与数据库进行多次访问,效率太慢了。
第二种:开启批处理指令,使用批处理的方式进行数据的新增
有两种方式开启批量处理
第一种:在mybatis的核心配置文件上开启 。
<settings>
<setting name="defaultExecutorType" value="BATCH"/></settings>
第二种方式是:在创建SqlSession对象的时候,指定开启批处理
sqlSession = sessionFactory.openSession(ExecutorType.BATCH,false);
查看控制台效果
这里语句只执行了一次,效率变高了。