Mybatis学习(三)-基于代理实现CRUD操作

一、增删改查

1.1、根据id查用户

1)持久层添加方法

public interface UserMapper {

    //通过id查询用户
    User findUserById(Integer id);

}

2)配置文件配置

<!--通过id查询用户-->
<select id="findUserById" parameterType="Integer" resultType="com.dianchou.domain.User">
    select * from user where id = #{id}
</select>

3)测试

package com.dianchou.test;

import com.dianchou.dao.UserMapper;
import com.dianchou.domain.QueryVo;
import com.dianchou.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.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;


public class MybatisTest {
    private InputStream in = null;
    private SqlSessionFactoryBuilder builder =null;
    private SqlSessionFactory factory = null;
    private SqlSession sqlSession = null;
    private UserMapper mapper = null;

    @Before
    public void init() throws IOException {
        //1.读取配置文件
        in = Resources.getResourceAsStream("mybatis-config.xml");
        //2.创建SqlSessionFactory构建者对象
        builder= new SqlSessionFactoryBuilder();
        //3.创建SqlSessionFactory
        factory = builder.build(in);
        //4.使用 SqlSessionFactory 生产 SqlSession 对象
        sqlSession = factory.openSession();
        //5.使用 SqlSession 创建 dao 接口的代理对象
        mapper = sqlSession.getMapper(UserMapper.class);
    }

    @Test
    public void testFindUserById(){
        User user = mapper.findUserById(50);
        System.out.println(user);
    }

    @After
    public void destroy() throws IOException {
        //事务提交
        sqlSession.commit();

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

1.2、保存用户

1)持久层编写方法

//保存用户
int saveUser(User user);

2)配置文件配置

<!--保存用户-->
<insert id="saveUser" parameterType="com.dianchou.domain.User">
    insert into user(username,address,sex,birthday) values(#{username},#{address},#{sex},#{birthday})
</insert>

3)测试

@Test
public void testSaveUser(){
    User user = new User(null,"Tom2","beijing","",new Date());
    int i = mapper.saveUser(user);
    System.out.println(i);
}

image

注意:当需要获取插入的id时:

<!--保存用户-->
<insert id="saveUser" parameterType="com.dianchou.domain.User">
    <!-- 配置保存时获取插入的 id-->
    <selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
        select last_insert_id()
    </selectKey>
    insert into user(username,address,sex,birthday) values(#{username},#{address},#{sex},#{birthday})
</insert>

测试:

@Test
public void testSaveUser2(){
    User user = new User();
    user.setUsername("AA");
    user.setAddress("shenzhen");
    user.setSex("");
    user.setBirthday(new Date());
    System.out.println("保存之前: " + user );
    mapper.saveUser(user);
    System.out.println("保存之后: " + user );
}

image

1.3、用户更新

1)持久层编写方法

//更新用户
int updateUser(User user);

2)配置文件配置

<!--更新用户-->
<update id="updateUser" parameterType="com.dianchou.domain.User">
    update user set username=#{username},address=#{address},sex=#{sex},birthday=#{birthday} where id=#{id}
</update>

3)测试

@Test
public void testUpdateUser(){
    User user = new User();
    user.setId(59);
    user.setUsername("AA");
    user.setAddress("shenzhen");
    user.setSex("");
    user.setBirthday(new Date());
    int i = mapper.updateUser(user);
    System.out.println(i);
}
image

1.4、删除用户

1)持久层编写方法

//删除用户
int deleteUser(Integer id);

2)配置文件配置

<!--删除用户-->
<delete id="deleteUser" parameterType="Integer">
    delete from user where id = #{id}
</delete>

3)测试

@Test
public void testDeleteUser(){
    int i = mapper.deleteUser(48);
    System.out.println(i);
}
image

1.5、模糊查询

1)持久层编写方法

//通过名称模糊查询1
List<User> findUserByName(String username);

2)配置文件

<!--通过姓名模糊查询-->
<select id="findUserByName" parameterType="String" resultType="com.dianchou.domain.User">
    select * from user where username like #{username}
</select>

3)测试

我们在配置文件中没有加入%来作为模糊查询的条件,所以在传入字符串实参时,就需要给定模糊查询的标识%。配置文件中的#{username}也只是一个占位符,所以 SQL 语句显示为“?”

@Test
public void testFindUserByName(){
    List<User> users = mapper.findUserByName("%A%");
    for (User user : users) {
        System.out.println(user);
    }
}
image

另一种方式

<!--通过姓名模糊查询2-->
<select id="findUserByName2" parameterType="String" resultType="com.dianchou.domain.User">
    select * from user where username like '%${value}%'
</select>
@Test
public void testFindUserByName2(){
    List<User> users = mapper.findUserByName2("A");
    for (User user : users) {
        System.out.println(user);
    }
}
image

将原来的#{}占位符,改成了${value}。注意如果用模糊查询的这种写法,那么${value}的写 法就是固定的,不能写成其它名字

说明:#{}与${}的区别

1)#{}表示一个占位符号

通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型转换, #{}可以有效防止 sql 注入。 #{}可以接收简单类型值或 pojo 属性值。 如果 parameterType 传输单个简单类 型值,#{}括号中可以是 value 或其它名称。

2)${}表示拼接 sql 串

通过${}可以将 parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换, ${}可以接收简 单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值,${}括号中只能是 value

image

1.6、聚合查询

1)持久层编写方法

//查询总记录数
int findTotal();

2)配置文件

<!--查询总记录数-->
<select id="findTotal" resultType="int">
    select count(id) from user
</select>

3)测试

@Test
public void testFindTotal(){
    int total = mapper.findTotal();
    System.out.println(total);
}
image

二、映射文件相关参数

2.1、parameterType配置参数类型

该属性的取值可以 是基本类型,引用类型(例如:String 类型),还可以是实体类类型(POJO 类)。同时也可以使用实体类的包装类

1)基本类型和String我们可以直接写类型名称,也可以使用包名.类名的方式,例 如 :java.lang.String。

https://mybatis.org/mybatis-3/zh/configuration.html#typeAliases

2)实体类类型,目前我们只能使用全限定类名。 究其原因,是 mybaits 在加载时已经把常用的数据类型注册了别名,从而我们在使用时可以不写包名, 而我们的是实体类并没有注册别名,所以必须写全限定类名

3)TypeAliasRegistry.java的源码

image

2.2、传递 pojo 包装对象

开发中通过 pojo 传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。

Pojo 类中包含 pojo。

需求:根据用户名查询用户信息,查询条件放到 QueryVo 的 user 属性中。

1)编写 QueryVo

//查询条件对象
public class QueryVo {
    private User user;

    public User getUser() {
        return user;
    }

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

2)编写持久层接口

public interface UserMapper {

    //根据QueryVo查询条件来查询用户
    List<User> findByQueryVo(QueryVo vo);
}

3)持久层接口的映射文件

<!--根据QueryVo查询条件来查询用户-->
<select id="findByQueryVo" parameterType="com.dianchou.domain.QueryVo" resultType="com.dianchou.domain.User">
    select * from user where username like #{user.username}
</select>

4)测试

@Test
public void testFindByQueryVo(){
    QueryVo vo = new QueryVo();
    User user = new User();
    user.setUsername("%A%");
    vo.setUser(user);
    List<User> users = mapper.findByQueryVo(vo);
    for (User u : users) {
        System.out.println(u);
    }
}
image

2.3、resultType 配置结果类型

resultType 属性可以指定结果集的类型,它支持基本类型和实体类类型。 需要注意的是,它和 parameterType 一样,如果注册过类型别名的,可以直接使用别名。没有注册过的必须 使用全限定类名

实体类属性:

image

表列名:

image

实体类属性和数据库表的列名不一致情况下,有两种解决方法:

1)sql语句使用别名

<!--查询所有用户-->
<select id="findAll" resultType="com.dianchou.domain.User">
    <!--select * from user-->
    select id userId,username userName,address userAddress,sex userSex,birthday userBirthday from user
</select>

2)使用resultMap,将实体类属性与表列名一一对应

<!--配置实体类属性与数据库字段一一对应-->
<resultMap id="userMap" type="com.dianchou.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>
<!--查询所有用户-->
<select id="findAll" resultMap="userMap">
    select * from user
</select>

2.4、resultMap 结果类型

resultMap 标签可以建立查询的列名和实体类的属性名称不一致时建立对应关系。从而实现封装。

在 select 标签中使用 resultMap 属性指定引用即可。同时 resultMap 可以实现将查询结果映射为复杂类型的 pojo,比如在查询结果映射对象中包括 pojo 和 list 实现一对一查询和一对多查询。

<!--
    type 属性:指定实体类的全限定类名
    id 属性:给定一个唯一标识,是给查询 select 标签引用用的
    id 标签:用于指定主键字段
    result 标签:用于指定非主键字段
    column 属性:用于指定数据库列名
    property 属性:用于指定实体类属性名称
-->
<!--配置实体类属性与数据库字段一一对应-->
<resultMap id="userMap" type="com.dianchou.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>
<!--查询所有用户-->
<select id="findAll" resultMap="userMap">
    select * from user
<!--select id userId,username userName,address userAddress,sex userSex,birthday userBirthday from user-->
</select>

三、传统 DAO 层开发[了解]

使用 Mybatis 开发 Dao,通常有两个方法,即原始 Dao 开发方式和 Mapper 接口代理开发方式。而现在主流 的开发方式是接口代理开发方式,这种方式总体上更加简便。

介绍一下基于传统编写 Dao 实现类的开发方式

image

1)持久层接口及实现类

package com.itheima.dao;

import com.itheima.domain.User;

import java.util.List;

/**
 * 用户的持久层接口
 */
public interface IUserDao {

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

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

    /**
     * 更新用户
     */
    void updateUser(User user);

    /**
     * 根据Id删除用户
     */
    void deleteUser(Integer userId);

    /**
     * 根据id查询用户信息
     */
    User findById(Integer userId);

    /**
     * 根据名称模糊查询用户信息
     */
    List<User> findByName(String username);

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

}
View Code
package com.itheima.dao.impl;

import com.itheima.dao.IUserDao;
import com.itheima.domain.User;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import java.util.List;

public class UserDaoImpl implements IUserDao {

    private SqlSessionFactory factory;

    public UserDaoImpl(SqlSessionFactory factory){
        this.factory = factory;
    }

    public List<User> findAll() {
        //1.根据factory获取SqlSession对象
        SqlSession session = factory.openSession();
        //2.调用SqlSession中的方法,实现查询列表
        List<User> users = session.selectList("com.itheima.dao.IUserDao.findAll");//参数就是能获取配置信息的key
        //3.释放资源
        session.close();
        return users;
    }

    public void saveUser(User user) {
        //1.根据factory获取SqlSession对象
        SqlSession session = factory.openSession();
        //2.调用方法实现保存
        session.insert("com.itheima.dao.IUserDao.saveUser",user);
        //3.提交事务
        session.commit();
        //4.释放资源
        session.close();
    }

    public void updateUser(User user) {
        //1.根据factory获取SqlSession对象
        SqlSession session = factory.openSession();
        //2.调用方法实现更新
        session.update("com.itheima.dao.IUserDao.updateUser",user);
        //3.提交事务
        session.commit();
        //4.释放资源
        session.close();
    }

    public void deleteUser(Integer userId) {
        //1.根据factory获取SqlSession对象
        SqlSession session = factory.openSession();
        //2.调用方法实现更新
        session.update("com.itheima.dao.IUserDao.deleteUser",userId);
        //3.提交事务
        session.commit();
        //4.释放资源
        session.close();
    }

    public User findById(Integer userId) {
        //1.根据factory获取SqlSession对象
        SqlSession session = factory.openSession();
        //2.调用SqlSession中的方法,实现查询一个
        User user = session.selectOne("com.itheima.dao.IUserDao.findById",userId);
        //3.释放资源
        session.close();
        return user;
    }

    public List<User> findByName(String username) {
        //1.根据factory获取SqlSession对象
        SqlSession session = factory.openSession();
        //2.调用SqlSession中的方法,实现查询列表
        List<User> users = session.selectList("com.itheima.dao.IUserDao.findByName",username);
        //3.释放资源
        session.close();
        return users;
    }

    public int findTotal() {
        //1.根据factory获取SqlSession对象
        SqlSession session = factory.openSession();
        //2.调用SqlSession中的方法,实现查询一个
        Integer count = session.selectOne("com.itheima.dao.IUserDao.findTotal");
        //3.释放资源
        session.close();
        return count;
    }
}
View Code

2)持久层映射配置

<?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="com.itheima.dao.IUserDao">

    <!-- 查询所有 -->
    <select id="findAll" resultType="com.itheima.domain.User">
        select * from user;
    </select>

    <!-- 保存用户 -->
    <insert id="saveUser" parameterType="com.itheima.domain.User">
        <!-- 配置插入操作后,获取插入数据的id -->
        <selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
            select last_insert_id();
        </selectKey>
        insert into user(username,address,sex,birthday)values(#{username},#{address},#{sex},#{birthday});
    </insert>

    <!-- 更新用户 -->
    <update id="updateUser" parameterType="com.itheima.domain.User">
        update user set username=#{username},address=#{address},sex=#{sex},birthday=#{birthday} where id=#{id}
    </update>

    <!-- 删除用户-->
    <delete id="deleteUser" parameterType="java.lang.Integer">
        delete from user where id = #{uid}
    </delete>

    <!-- 根据id查询用户 -->
    <select id="findById" parameterType="INT" resultType="com.itheima.domain.User">
        select * from user where id = #{uid}
    </select>

    <!-- 根据名称模糊查询 -->
    <select id="findByName" parameterType="string" resultType="com.itheima.domain.User">
          select * from user where username like #{name}
   </select>

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

3)测试

package com.itheima.test;

import com.itheima.dao.IUserDao;
import com.itheima.dao.impl.UserDaoImpl;
import com.itheima.domain.User;
import org.apache.ibatis.io.Resources;
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;

/**
 * 测试mybatis的crud操作
 */
public class MybatisTest {

    private InputStream in;
    private IUserDao userDao;

    @Before//用于在测试方法执行之前执行
    public void init()throws Exception{
        //1.读取配置文件,生成字节输入流
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.获取SqlSessionFactory
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //3.使用工厂对象,创建dao对象
        userDao = new UserDaoImpl(factory);
    }

    @After//用于在测试方法执行之后执行
    public void destroy()throws Exception{
        //6.释放资源
        in.close();
    }

    /**
     * 测试查询所有
     */
    @Test
    public void testFindAll(){
        //5.执行查询所有方法
        List<User> users = userDao.findAll();
        for(User user : users){
            System.out.println(user);
        }

    }
    /**
     * 测试保存操作
     */
    @Test
    public void testSave(){
        User user = new User();
        user.setUsername("dao impl user");
        user.setAddress("北京市顺义区");
        user.setSex("");
        user.setBirthday(new Date());
        System.out.println("保存操作之前:"+user);
        //5.执行保存方法
        userDao.saveUser(user);

        System.out.println("保存操作之后:"+user);
    }

    /**
     * 测试更新操作
     */
    @Test
    public void testUpdate(){
        User user = new User();
        user.setId(50);
        user.setUsername("userdaoimpl update user");
        user.setAddress("北京市顺义区");
        user.setSex("");
        user.setBirthday(new Date());

        //5.执行保存方法
        userDao.updateUser(user);
    }

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

    /**
     * 测试删除操作
     */
    @Test
    public void testFindOne(){
        //5.执行查询一个方法
        User  user = userDao.findById(50);
        System.out.println(user);
    }

    /**
     * 测试模糊查询操作
     */
    @Test
    public void testFindByName(){
        //5.执行查询一个方法
        List<User> users = userDao.findByName("%王%");
        for(User user : users){
            System.out.println(user);
        }
    }

    /**
     * 测试查询总记录条数
     */
    @Test
    public void testFindTotal(){
        //5.执行查询一个方法
        int count = userDao.findTotal();
        System.out.println(count);
    }

}
View Code
原文地址:https://www.cnblogs.com/hujinzhong/p/13291651.html