zoukankan      html  css  js  c++  java
  • MyBatis03_CRUD

    本教程源码请访问:tutorial_demo
    通过前面的学习,我们对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属性值。

  • 相关阅读:
    李开复给学习计算机的学生的7点建议(转)
    linux 命令
    易中天的十句话
    11个笑话让你领悟人生
    心情不好的时候看看
    高校青年老师挣扎在辞职边缘 微薄工资继续啃老
    【33.00%】【vijos P1002】过河
    【33.33%】【codeforces 681D】Gifts by the List
    【19.05%】【codeforces 680D】Bear and Tower of Cubes
    【12.78%】【codeforces 677D】Vanya and Treasure
  • 原文地址:https://www.cnblogs.com/codeaction/p/12896917.html
Copyright © 2011-2022 走看看