03.【基于代理Dao的CRUD操作】

目录结构

在这里插入图片描述

  1. 实体类:QueryVo
package cn.luis.domain;

/**
 * @ClassName QueryVo
 * @Description 由多个对象组成一个查询条件实现数据的查询
 * @Author L
 * @Date 2020.03.01 20:32
 * @Version 1.0
 * @Remark TODO
 **/
public class QueryVo {
    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}

  1. IUserDao.java
package cn.luis.dao;

import cn.luis.domain.QueryVo;
import cn.luis.domain.User;

import java.util.List;

/**
 * @InterfaceName IUserDao
 * @Description 用户的持久层接口
 * @Author L
 * @Date 2020.02.29 15:31
 * @Version 1.0
 * @Remark TODO
 **/
public interface IUserDao {

    /**
     * @Description 查询所有用户
    **/
    List<User> findAll();

    /**
     * @Description 保存用户
    **/
    void saveUser(User user);

    /**
     * @Description 更新用户
     * @Return void
    **/
    void updateUser (User user);
    
    /**
     * @Description 根据Id删除用户
    **/
    void deleteUser(Integer userId);

    /**
     * @Description 根据Id查询用户信息
    **/
    User findById(Integer userId);
    
    /**
     * @Description 根据名称,模糊查询用户信息
    **/
    List<User> findByName(String username);

    /**
     * @Description 查询总用户数
    **/
    int findTotal();

    /**
     * @Description 根据queryVo中的条件查询用户
     * 把查询条件对象作为参数传递
     **/
    List<User> findUserByVo(QueryVo vo);
}
  1. IUserao.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">
<mapper namespace="cn.luis.dao.IUserDao">

    <!-- 配置 查询结果的列名和实体类的属性名的对应关系 【开发效率高】-->
    <resultMap id="userMap" type="cn.luis.domain.User">
        <!-- 主键字段的对应 -->
        <id property="userId" column="id"></id>
        <!--非主键字段的对应-->
        <result property="userName" column="username"></result>
        <result property="userAddress" column="address"></result>
        <result property="userSex" column="sex"></result>
        <result property="userBirthday" column="birthday"></result>
    </resultMap>

    <!--查询所有  【resultType】:结果集类型(封装到哪里去)-->
    <!--<select id="findAll" resultType="cn.luis.domain.User">-->
    <select id="findAll" resultMap="userMap">
        select * from user;

        <!--select id as userId,username as userName,address as userAddress,sex as userSex,birthday as userBirthday from user; 【执行效率高】-->
    </select>

    <!--保存用户  parameterType:参数类型  【OGNL表达式】:#{实体类属性名称}-->
    <insert id="saveUser" parameterType="cn.luis.domain.User">
        insert into user(username,address,sex,birthday)values(#{userName},#{userAddress},#{userSex},#{userBirthday});
        <!-- 插入操作成功后,获取插入数据的Id -->
        <!-- 【keyProperty】:Id属性名(实体类)【keyColumn】:Id列名(表) 【order】: 什么时候执行获取Id操作 【After】:在插入之后 -->
        <selectKey keyProperty="userId" keyColumn="id" resultType="int" order="AFTER">
            select last_insert_id();
        </selectKey>
    </insert>

    <!--更新用户-->
    <update id="updateUser" parameterType="cn.luis.domain.User">
        update user set username=#{userName},address=#{userAddress},sex=#{userSex},birthday=#{userBirthday} where id = #{userId};
    </update>

    <!--删除用户  【uid:占位符】,参数是基本类型或者基本类型包装类时,并且只有一个时,可随意命名-->
    <delete id="deleteUser" parameterType="Integer">
        delete from user where id = #{uid};
    </delete>

    <!--根据Id查询用户-->
    <select id="findById" parameterType="INT" resultMap="userMap">
        select * from user where id = #{uid};
    </select>

    <!--根据名称,模糊查询用户-->
    <select id="findByName" parameterType="String" resultMap="userMap">
        <!--【预处理方式】:like ? -->
        <!--select * from user where username like #{name};-->
        <!--【字符串拼接方式】 :like %小% -->
        select * from user where username like '%${value}%';
    </select>

    <!--获取用户的总记录条数-->
    <select id="findTotal" resultType="int">
        select count(id) from user;
    </select>

    <!-- 根据queryVo的条件查询用户 -->
    <!-- 【#{user.username}】:在QueryVo中有user属性,user是对象,要调用它的属性username -->
    <select id="findUserByVo" parameterType="cn.luis.domain.QueryVo" resultMap="userMap">
        select * from user where username like #{user.username};
    </select>
</mapper>
  1. 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">
<!-- mybatis的主配置文件 -->
<configuration>
    <!-- 配置环境 -->
    <environments default="mysql">
        <!-- 配置mysql的环境-->
        <environment id="mysql">
            <!-- 配置事务的类型-->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 配置数据源(连接池) -->
            <dataSource type="POOLED">
                <!-- 配置连接数据库的4个基本信息 -->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <!-- 指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件 -->
    <mappers>
        <mapper resource="cn/luis/dao/IUserMapper.xml"/>
    </mappers>
</configuration>
  1. 测试类
package cn.luis.test;

import cn.luis.dao.IUserDao;
import cn.luis.domain.QueryVo;
import cn.luis.domain.User;
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.After;
import org.junit.Before;
import org.junit.Test;

import java.io.InputStream;
import java.util.Date;
import java.util.List;

/**
 * @ClassName MybatisTest
 * @Description 测试mybatis的CRUD操作
 **/
public class MybatisTest {

    private InputStream in;
    private SqlSession sqlSession;
    private IUserDao userDao;

    // 用于在测试方法执行之前执行
    @Before
    public void init()  throws Exception {
        // 1.读取配置文件,生成字节输入流
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 2.获取sqlsessionfactory
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        // 3.获取sqlsession对象
        sqlSession = factory.openSession();
        // 4.获取dao的代理对象
        userDao = sqlSession.getMapper(IUserDao.class);
    }

    // 用于在测试方法执行完成后执行
    @After
    public void destory() throws Exception {
        // 提交事务
        sqlSession.commit();

        // 6.释放资源
        sqlSession.close();
        in.close();
    }

    /**
     * @Description 查询所有 (mysql在windows下不区分大小写,所以能把username封装到userName中)
    **/
    @Test
    public void testFindAll() {
        // 5.执行所有方法
        List<User> users = userDao.findAll();
        for (User user : users) {
            System.out.println(user);
        }
    }

    /**
     * @Description 测试保存操作
    **/
    @Test
    public void testFindSave() {
        User user = new User();
        user.setUserName("mybatis last insertid");
        user.setUserAddress("沈阳");
        user.setUserSex("男"); // 查看数据库这里的赋值类型
        user.setUserBirthday(new Date());
        System.out.println("保存操作之前:" + user);
        // 5.执行保存方法
        userDao.saveUser(user);
        System.out.println("保存操作之后:" + user);
    }

    /**
     * @Description 测试更新操作
    **/
    @Test
    public void testUpdate() {
        User user = new User();
        // 给id赋值
        user.setUserId(45);
        user.setUserName("mybatis updateuser");
        user.setUserAddress("沈阳");
        user.setUserSex("女"); // 查看数据库这里的赋值类型
        user.setUserBirthday(new Date());
        // 5.执行保存方法
        userDao.updateUser(user);
    }

    /**
     * @Description 测试删除操作
    **/
    @Test
    public void testDelete() {
        // 5.执行删除方法
        userDao.deleteUser(49);
    }

    /**
     * @Description 测试查询一个方法
    **/
    @Test
    public void testFindOne() {
        User user = userDao.findById(45);
        System.out.println(user);
    }

    /**
     * @Description 测试模糊查询操作
    **/
    @Test
    public void testFindByName() {
        //List<User> users = userDao.findByName("%小%");
        List<User> users = userDao.findByName("小");
        for (User user : users) {
            System.out.println(user);
        }
    }

    /**
     * @Description 测试查询总记录条数
     * 支持聚合函数的查询
    **/
    @Test
    public void testFindTotal() {
        int count = userDao.findTotal();
        System.out.println(count);
    }

    /**
     * @Description 测试查询总记录条数
     **/
    @Test
    public void testFindByVo() {
        QueryVo vo = new QueryVo();
        User user = new User();
        user.setUserName("%王%");
        vo.setUser(user);
        List<User> users = userDao.findUserByVo(vo);
        for (User u : users) {
            System.out.println(u);
        }
    }

}

OGNL表达式

Object Graphic Navigation Language
  对象	 图	    导航	     语言

它是通过对象的取值方法来获取数据。在写法上把get给省略了。

比如:我们获取用户的名称:

  • 类中的写法:user.getUsername();
  • OGNL表达式写法:user.username

mybatis中为什么能直接写username,而不用user呢?

因为在parameterType中已经提供了属性所属的类,所以此时不需要写对象名

parameterType(输入类型)

可以传递简单类型,也可以传递pojo对象

Mybatis 使用ognl表达式解析对象字段的值,#{}或者${}括号中的值为pojo属性名称。

传递pojo对象

开发中通过pojo传递查询条件,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。
Pojo类中包含pojo。
需求:根据用户名查询用户信息,查询条件放到QueryVo的user属性中。

Mapper.xml文件

<!-- 根据queryVo的条件查询用户 -->
<!-- 【#{user.username}】:在QueryVo中有user属性,user是对象,要调用它的属性username -->
    <select id="findUserByVo" parameterType="cn.luis.domain.QueryVo" resultMap="userMap">
        select * from user where username like #{user.userName};
    </select>

Mapper接口

    /**
     * @Description 根据queryVo中的条件查询用户
     * 把查询条件对象作为参数传递
     **/
    List<User> findUserByVo(QueryVo vo);

测试类

    /**
     * @Description 测试查询总记录条数
     **/
    @Test
    public void testFindByVo() {
        QueryVo vo = new QueryVo();
        User user = new User();
        user.setUserName("%王%");
        vo.setUser(user);
        List<User> users = userDao.findUserByVo(vo);
        for (User u : users) {
            System.out.println(u);
        }
    }

结果

User{userId=41, userName='老王', userAddress='北京', userSex='男', userBirthday=Tue Feb 27 17:47:08 CST 2018}
User{userId=42, userName='小二王', userAddress='北京金燕龙', userSex='女', userBirthday=Fri Mar 02 15:09:37 CST 2018}
User{userId=43, userName='小二王', userAddress='北京金燕龙', userSex='女', userBirthday=Sun Mar 04 11:34:34 CST 2018}
User{userId=46, userName='老王', userAddress='北京', userSex='男', userBirthday=Wed Mar 07 17:37:26 CST 2018}

具体代码见上!

resultType(输出类型)

  • 可以输出简单类型
 <!--获取用户的总记录条数-->
    <select id="findTotal" resultType="int">
        select count(id) from user;
    </select>
  • 可以输出pojo对象(查询一个)
   	<!--根据Id查询用户-->
    <select id="findById" parameterType="INT" resultType="cn.luis.domain.User">
        select * from user where id = #{uid};
    </select>
  • 可以输出polo列表(查询所有)
 <!--根据名称,模糊查询用户-->
    <select id="findByName" parameterType="String" resultType="cn.luis.domain.User">
        <!--【预处理方式】:like ? -->
        <!--select * from user where username like #{name};-->
        <!--【字符串拼接方式】 :like %小% -->
        select * from user where username like '%${value}%';
    </select>

测试类

 	@Test
    public void testFindByName() {
        //【预处理方式】:like ? --> 【推荐】
        List<User> users = userDao.findByName("%小%");
        // 【字符串拼接方式】 :like %小% -->
        // List<User> users = userDao.findByName("小");
        for (User user : users) {
            System.out.println(user);
        }
    }

CRUD中可能遇到的问题

1. 参数的传递以及返回值的封装

  • mysql在windows下不区分大小写,所以能把username封装到userName中

要修改OGNL表达式中的实体类属性名称与之匹配才行

<!--保存用户  parameterType:参数类型  OGNL表达式:#{实体类属性名称}-->
    <insert id="saveUser" parameterType="cn.luis.domain.User">
        insert into user(username,address,sex,birthday)values(#{userName},#{userAddress},#{userSex},#{userBirthday});
        <!-- 插入操作成功后,获取插入数据的Id -->
        <!-- keyProperty:Id属性名(实体类)keyColumn:Id列名(表) order: 什么时候执行获取Id操作 After:在插入之后 -->
        <selectKey keyProperty="userId" keyColumn="id" resultType="int" order="AFTER">
            select last_insert_id();
        </selectKey>
    </insert>

2. 解决实体类属性和数据库列名不对应的两种方式

  1. 在sql语句中起别名 【执行效率高】
<!--查询所有  【resultType】:结果集类型(封装到哪里去)-->
    <select id="findAll" resultType="cn.luis.domain.User">
        <!-- select * from user; -->
		select id as userId,username as userName,address as userAddress,
        	sex as userSex,birthday as userBirthday from user;
    </select>
  1. 采用配置resultMap方式 【开发效率高】

    配置查询结果的类名和实体类属性名的对应关系

    <!-- 配置 查询结果的列名和实体类的属性名的对应关系 【开发效率高】-->
    <resultMap id="userMap" type="cn.luis.domain.User">
        <!-- 主键字段的对应 -->
        <id property="userId" column="id"></id>
        <!--非主键字段的对应-->
        <result property="userName" column="username"></result>
        <result property="userAddress" column="address"></result>
        <result property="userSex" column="sex"></result>
        <result property="userBirthday" column="birthday"></result>
    </resultMap>

<!--查询所有  【resultType】:结果集类型(封装到哪里去)-->
    <select id="findAll" resultMap="userMap">
        select * from user;
    </select>
发布了36 篇原创文章 · 获赞 14 · 访问量 3586

猜你喜欢

转载自blog.csdn.net/qq_39720594/article/details/105223427
03.