03_MyBatis的CRUD

通过前面的学习,我们对MyBatis的概念和环境搭建已经有了一个基本的了解,接下来我们学习一下MyBatis的CRUD。

这篇教程的环境要求如下:

  1. 持久层接口和持久层接口的映射配置文件必须在相同的包下;
  2. 持久层接口的映射配置文件mapper标签的namespace属性取值必须是持久层接口的全限定类名;
  3. 持久层接口的映射配置文件SQL语句标签<select><insert><delete><update>的属性必须和持久层接口的方法名相同。

注意:这篇教程是“02_MyBatis快速入门”的延续,环境和02当中完全相同,如果02没有配置运行成功,请返回认真学习。

一、根据id查询

1.1、在持久层接口IUserDao中添加相应方法

//根据id查询
User findById(Integer id);

1.2、在持久层接口的映射配置文件IUserDao.xml添加配置

<select id="findById" parameterType="java.lang.Integer" resultType="org.codeaction.domain.User">
    select * from user where id=#{id}
</select>

resultType属性:用于指定结果集的类型;

parameterType属性:用于指定传入参数的类型;

#{}:它代表占位符, 相当于原来 jdbc 部分所学的?,都是用于执行语句时替换实际的数据,具体的数据是由#{}里面的内容决定的,由于数 据类型是基本类型,所以此处可以随意写。

1.3、修改测试类MyBatisTest

package org.codeaction.test;

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.codeaction.dao.IUserDao;
import org.codeaction.domain.User;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;

public class MyBatisTest {
    private InputStream in;
    private SqlSession session;

    /**
     *
     * 在所有测试方法运行之前运行,进行初始化操作
     * @throws IOException
     */
    @Before
    public void init() throws IOException {
        //读取配置文件
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory工厂
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(in);
        //使用工厂生产SqlSession对象
        session = factory.openSession();
    }

    /**
     * 在所有测试方法运行之后运行,进行清理操作
     * @throws IOException
     */
    @After
    public void destroy() throws IOException {
        //提交事务
        session.commit();
        //释放资源
        session.close();
        in.close();
    }

    @Test
    public void testFindAll() throws IOException {
        //使用SqlSession创建Dao接口的代理对象
        IUserDao userDao = session.getMapper(IUserDao.class);
        //使用代理对象执行方法
        List<User> list = userDao.findAll();
        list.forEach(System.out::println);
    }

    @Test
    public void testFindById() {
        IUserDao userDao = session.getMapper(IUserDao.class);
        User user = userDao.findById(41);
        System.out.println(user);
    }
}

由于我们后面要写多个测试方法,每个测试方法中有一些步骤是完全相同的,那么我们把重复的操作抽取出来,进行了如下操作:

  • 创建了init()方法,进行初始化操作,并添加@Before注解,从而init()方法可以在任意一个被测试方法运行之前运行;

  • 创建了destroy()方法,进行销毁操作,并添加@After注解,从而destroy()方法可以在任意一个被测试方法运行之后运行。

运行testFindById()方法,结果如下:

User{id=41, username='王一', birthday=Tue Dec 27 17:47:08 CST 2011, sex='男', address='北京'}

二、添加操作

2.1、在持久层接口IUserDao中添加相应方法

//添加用户
Integer add(User user);

2.2、在持久层接口的映射配置文件IUserDao.xml添加配置

<insert id="add" parameterType="org.codeaction.domain.User">
	insert into user(username, birthday, sex, address) values(#{username}, #{birthday}, #{sex}, #{address})
</insert>

parameterType属性:代表参数的类型,因为我们要传入的是一个类的对象,所以类型就写类的全名称;

#{}:它代表占位符,相当于原来JDBC部分所学的?,都是用于执行语句时替换实际的数据,具体的数据是由#{}里面的内容决定的;

#{}中内容的写法:由于我们保存方法的参数是一个User对象,此处要写User对象中的属性名称,它用的是OGNL表达式;

OGNL表达式:Object Graphic Navigation Language(对象图导航语言)它是Apache提供的一种表达式语言,它是按照一定的语法格式来 获取数据。语法格式就是使用#{对象.对象}的方式,#{user.username}它会先去找user对象,然后在user对象中找到username属性,并调 用getUsername()方法把值取出来,但是我们在parameterType属性上指定了实体类名称,所以可以省略user.而直接写username。

2.3、在测试类MyBatisTest添加测试方法

@Test
public void testAdd() {
    User user = new User();
    user.setUsername("张三");
    user.setBirthday(new Date());
    user.setSex("男");
    user.setAddress("南昌");

    IUserDao userDao = session.getMapper(IUserDao.class);
    System.out.println(result);
}

注意:测试类destroy()方法中一定要有“提交事务”(上面的代码已经添加)操作,否则添加、删除、修改不会成功,但是会回滚。

运行add()方法,在控制台打印“1”,并且数据库中添加了相应的记录,证明添加成功。

2.4、返回新增用户id

新增用户后,同时还要返回当前新增用户的id值,因为id是由数据库的自动增长来实现的,所以就相当于我们要在新增后将自动增长 auto_increment 的值返回。

修改持久层接口的映射配置文件IUserDao.xml

<insert id="add" parameterType="org.codeaction.domain.User">
    <selectKey keyProperty="id" keyColumn="id" resultType="java.lang.Integer" order="AFTER">
        select last_insert_id()
    </selectKey>
    insert into user(username, birthday, sex, address) values(#{username}, #{birthday}, #{sex}, #{address})
</insert>

keyProperty:selectKey语句结果应该被设置到的目标属性;

keyColumn:主键对应的列名;

resultType:结果的类型;

order:可以设置为BEFORE或AFTER。如果设置为BEFORE,那么它首先会生成主键,设置keyProperty再执行插入语句。如果设置为 AFTER,那么先执行插入语句,然后是selectKey中的语句,MySQL中设置为AFTER就可以。

修改测试类中testAdd()方法

@Test
public void testAdd() {
    User user = new User();
    user.setUsername("张三");
    user.setBirthday(new Date());
    user.setSex("男");
    user.setAddress("南昌");

    IUserDao userDao = session.getMapper(IUserDao.class);
    Integer result = userDao.add(user);
    //打印User对象,以便于我们观察是否生成了id
    System.out.println(user);
    System.out.println(result);
}

运行add()方法,控制台输出如下:

User{id=58, username='张三', birthday=Fri May 15 18:50:03 CST 2020, sex='男', address='南昌'}
1

结果中id存在值,证明返回了新增用户的id。

三、更新操作

3.1、在持久层接口IUserDao中添加相应方法

//更新用户
Integer chg(User user);

3.2、在持久层接口的映射配置文件IUserDao.xml添加配置

<update id="chg" parameterType="org.codeaction.domain.User">
    update user set username=#{username}, birthday=#{birthday}, sex=#{sex}, address=#{address} where id=#{id}
</update>

3.3、在测试类MyBatisTest添加测试方法

@Test
public void testChg() {
    User user = new User();
    user.setId(58);
    user.setUsername("张三");
    user.setBirthday(new Date());
    user.setSex("男");
    user.setAddress("长沙");
    IUserDao userDao = session.getMapper(IUserDao.class);
    Integer result = userDao.chg(user);
    System.out.println(result);
}

四、删除操作

4.1、在持久层接口IUserDao中添加相应方法

Integer del(Integer id);

4.2、在持久层接口的映射配置文件IUserDao.xml添加配置

<delete id="del" parameterType="java.lang.Integer">
    delete from user where id=#{id}
</delete>

4.3、在测试类MyBatisTest添加测试方法

@Test
public void testDel() {
    IUserDao userDao = session.getMapper(IUserDao.class);
    Integer result = userDao.del(58);
    System.out.println(result);
}

五、使用聚合函数查询

5.1、在持久层接口IUserDao中添加相应方法

Integer findTotal();

5.2、在持久层接口的映射配置文件IUserDao.xml添加配置

<select id="findTotal" resultType="java.lang.Integer">
    select count(id) from user
</select>

5.3、在测试类MyBatisTest添加测试方法

@Test
public void testFindTotal() {
    IUserDao userDao = session.getMapper(IUserDao.class);
    Integer count = userDao.findTotal();
    System.out.println(count);
}

六、模糊查询

需求:查询所有名字中带”王“的User。

6.1、在持久层接口IUserDao中添加相应方法

List<User> findByName(String username);

6.2、在持久层接口的映射配置文件IUserDao.xml添加配置

<select id="findByName" parameterType="java.lang.String" resultType="org.codeaction.domain.User">
    select * from user where username like #{username}
</select>

6.3、在测试类MyBatisTest添加测试方法

@Test
public void testFindByName() throws Exception{
    IUserDao userDao = session.getMapper(IUserDao.class);
    List<User> users = userDao.findByName("%王%");

    users.forEach(System.out::println);
}

运行测试方法,部分控制台信息如下:

==> Preparing: select * from user where username like ? 
==> Parameters: %王%(String)
Total: 3
User{id=41, username='王一', birthday=Tue Dec 27 17:47:08 CST 2011, sex='男', address='北京'}
User{id=42, username='王二', birthday=Sat Mar 12 15:09:37 CST 2011, sex='女', address='上海'}
User{id=46, username='老王', birthday=Sat Aug 07 17:37:26 CST 1999, sex='女', address='拉萨'}

#{username}被MyBatis当成了一个整体来处理,编译之后当成了一个占位符。

6.4 模糊查询的另一种配置

6.4.1、持久层接口的映射配置文件修改

<select id="findByName" parameterType="java.lang.String" resultType="org.codeaction.domain.User">
    select * from user where username like '%${value}%'
</select>

6.4.2、测试方法修改

@Test
public void test11FindByName() throws Exception{
    IUserDao userDao = session.getMapper(IUserDao.class);
    List<User> users = userDao.findByName("王");

    users.forEach(System.out::println);
}

运行测试方法,部分控制台信息如下:

==>  Preparing: select * from user where username like '%王%' 
==> Parameters: 
Total: 3
User{id=41, username='王一', birthday=Tue Dec 27 17:47:08 CST 2011, sex='男', address='北京'}
User{id=42, username='王二', birthday=Sat Mar 12 15:09:37 CST 2011, sex='女', address='上海'}
User{id=46, username='老王', birthday=Sat Aug 07 17:37:26 CST 1999, sex='女', address='拉萨'}

通过对比可以发现,程序代码中不需要加入模糊查询的匹配符%了 ,执行结果是一样的,但是执行的语句不一样。

6.5、#{}与${}的区别

#{}表示占位符

通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,#{}可以有效防止SQL注入。#{}可以接收简单类型值或pojo属性值。

${}表示拼接SQL

通过${}可以将parameterType传入的内容拼接在SQL中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值。

猜你喜欢

转载自www.cnblogs.com/codeaction/p/12896917.html