MyBatis使用篇(三)—— 单表的CURD操作

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_36378917/article/details/84978388

1、自定义DAO接口实现类

  CURD操作,即指对数据库实体对象的增(Create)、改(Update)、查(Read)、删(Delete)操作。

1.1 环境搭建

  该测试环境是在上一节的基础上进行的,上一节的环境搭建详见《MyBatis使用篇(二)—— MyBatis开发环境搭建》

  首先修改“com.ccff.mybatis.dao.IUserDao”,为数据库操作添加接口方法,具体代码修改如下:

package com.ccff.mybatis.dao;

import com.ccff.mybatis.model.User;

import java.util.List;
import java.util.Map;

public interface IUserDao {
    //插入一个用户
    public void insertUser(User user);
    //插入一个用户,并获取该用户的id
    public void insertUserCatchId(User user);

    //根据id删除某个用户
    public void deleteUserById(int id);

    //修改某个用户
    public void updateUser(User user);

    //查询所有用户,以List形式返回
    public List<User> findAllUserToList();
    //查询所有用户,以Map形式返回
    public Map<String,User> findAllUserToMap();
    //根据id查询某个用户
    public User findUserById(int id);
    //根据username模糊查询某个用户
    public List<User> findUserByName(String username);
}

  然后,修改IUserDao的实现类IUserDaoImpl。除去在上一节已经实现的findUserById方法外,对其他方法均空实现,具体代码如下:

package com.ccff.mybatis.dao;

import com.ccff.mybatis.datasource.DataConnection;
import com.ccff.mybatis.model.User;
import org.apache.ibatis.session.SqlSession;

import java.io.IOException;
import java.util.List;
import java.util.Map;

public class IUserDaoImpl implements IUserDao {
    private SqlSession sqlSession;
    private DataConnection dataConnection;

    public IUserDaoImpl(){
        super();
        try {
            DataConnection dataConnection = new DataConnection();
            sqlSession = dataConnection.getSqlSession();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public SqlSession getSqlSession() {
        return sqlSession;
    }

    public void setSqlSession(SqlSession sqlSession) {
        this.sqlSession = sqlSession;
    }

    public DataConnection getDataConnection() {
        return dataConnection;
    }

    public void setDataConnection(DataConnection dataConnection) {
        this.dataConnection = dataConnection;
    }

    @Override
    public void insertUser(User user) {

    }

    @Override
    public void insertUserCatchId(User user) {

    }

    @Override
    public void deleteUserById(int id) {

    }

    @Override
    public void updateUser(User user) {

    }

    @Override
    public List<User> findAllUserToList() {
        return null;
    }

    @Override
    public Map<String, User> findAllUserToMap() {
        return null;
    }

    @Override
    public User findUserById(int id) {
        User user = sqlSession.selectOne("test.findUserById",id);
        this.close();
        return  user;
    }

    @Override
    public List<User> findUserByName(String username) {
        return null;
    }
    
    private void close(){
        sqlSession.close();
    }
}

  最后修改MyBatisTest测试类,具体代码如下:

package com.ccff.mybatis.test;

import com.ccff.mybatis.dao.IUserDao;
import com.ccff.mybatis.model.User;
import com.ccff.mybatis.dao.IUserDaoImpl;
import org.junit.Test;

import java.text.SimpleDateFormat;

public class MyBatisTest {
    private IUserDao userDao;

    public MyBatisTest(){
        super();
        userDao = new IUserDaoImpl();
    }

    @Test
    public void TestSelect() {
        User user = userDao.findUserById(1);
        System.out.println("姓名:"+user.getUsername());
        System.out.println("性别:"+user.getGender());
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyy-MM-dd");
        System.out.println("生日:"+simpleDateFormat.format(user.getBirthday()));
        System.out.println("所在地:"+user.getProvince());
    }
}

  至此,开发测试基础环境搭建完毕。

1.2 插入一个用户

  第一步,修改SQL语句映射文件Mapper.xml,添加insert标签插入语句,修改后具体代码如下所示:

<?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="test">
    <insert id="insertUser"  parameterType="com.ccff.mybatis.model.User">
        insert into user (username,password,gender,email,province,city,birthday) values (#{username},#{password},#{gender},#{email},#{province},#{city},#{birthday})
    </insert>
    <select id="findUserById" parameterType="int" resultType="com.ccff.mybatis.model.User">
      select * from user where id=#{id}
    </select>
</mapper>

  第二步,修改IUserDao的实现类IUserDaoImpl,填充insertUser方法,具体代码如下:

	@Override
    public void insertUser(User user) {
        sqlSession.insert("test.insertUser",user);
        sqlSession.commit();
        this.close();
    }

  第三步,修改MyBatisTest,测试insertUser方法,具体代码如下:

	package com.ccff.mybatis.test;

import com.ccff.mybatis.dao.IUserDao;
import com.ccff.mybatis.model.User;
import com.ccff.mybatis.dao.IUserDaoImpl;
import org.junit.Test;

import java.text.SimpleDateFormat;
import java.util.Date;

public class MyBatisTest {
    private IUserDao userDao;

    public MyBatisTest(){
        super();
        userDao = new IUserDaoImpl();
    }

    @Test
    public void TestInsertUser(){
        Date day = new Date();
        User user = new User("王五","123456","男","[email protected]","辽宁省","沈阳市",day);
        userDao.insertUser(user);
    }
}

  第四步,运行MyBatisTest后,查看日志信息如下:
在这里插入图片描述
  第五步,进入数据库后查看user表,发现刚刚插入的记录已经存在,说明插入执行成功。具体如下所示:
在这里插入图片描述

1.3 插入用户后用新id初始化插入对象

  回顾1.2小节中演示的插入用户信息的实例,我们发现其实我们在new一个插入的用户对象实例的时候并没有指定该用户实例对象的id值,但是当我们执行插入数据库操作时却可以得到一个自增的id值。

  那么,现在有这样一个问题值得我们思考:如何获取创建的插入用户实例对象的自增id呢?

  在MySQL中,在插入语句后执行如下语句,则会输出新插入记录的id。

select @@identity;
#或者
select last_insert_id();

  因此,在SQL映射文件的insert标签中,有一个名为“selectKey”的子标签用于获取新插入记录的主键值。以下两种写法均可以完成“使用新插入记录的主键值初始化被插入的对象”的功能。

	<insert id="insertUser" parameterType="com.ccff.mybatis.model.User">
        insert into user (username,password,gender,email,province,city,birthday) values (#{username},#{password},#{gender},#{email},#{province},#{city},#{birthday})
        <selectKey resultType="int" keyProperty="id" order="AFTER">
            select @@identity
        </selectKey>
	</insert>

	<insert id="insertUserCatchId" parameterType="com.ccff.mybatis.model.User">
        insert into user (username,password,gender,email,province,city,birthday) values (#{username},#{password},#{gender},#{email},#{province},#{city},#{birthday})
        <selectKey resultType="int" keyProperty="id" order="AFTER">
            select last_insert_id();
        </selectKey>
	</insert>

  其中,resultType指出获取的主键的类型;keyProperty指出主键在Java实体类中对应的属性名。此处会将获取的主键值直接封装到被插入的User对象中;order指出id的生成相对于insert语句的执行是在前还是在后。MySQL数据库表中的id,均是先执行insert语句,而后生成id,所以需要设置为AFTER。Oracle数据库表中的id则是在insert执行之前生成,所以需要设置为BEFORE。当前的MyBatis版本,不指定order属性,则会根据所用DBMS自动选择其值。

  接下来修改IUserDaoImpl,为其中的insertUserCatchId方法添加具体方法体。具体方法同之前的插入方法,代码如下:

	@Override
    public void insertUserCatchId(User user) {
        sqlSession.insert("test.insertUserCatchId",user);
        sqlSession.commit();
        this.close();
    }

  然后修改测试类MyBatisTest,添加测试方法TestInsertUserCatchId,具体代码如下:

	@Test
    public void TestInsertUserCatchId(){
        Date day = new Date();
        User user = new User("王五","123456","男","[email protected]","辽宁省","沈阳市",day);
        System.out.println("插入前User = "+user);
        userDao.insertUserCatchId(user);
        System.out.println("插入后User = "+user);
    }

  最后,执行测试代码后数据表中存在刚刚插入的数据,并且从控制台打印的日志中可以看到,插入前插入user对象的id为默认值0,而插入后user对象的id为刚刚插入数据库后数据表中自增id值,说明测试通过。
在这里插入图片描述
在这里插入图片描述

1.4 根据id删除某个用户

  第一步,修改SQL映射文件,添加delete标签和删除语句,具体如下。这里需要注意的是,这里的参数类型为int类型(基本数据类型),因此后面#{}里面的值可以是任意字符,仅起到占位符的作用。

	<delete id="deleteUserById" parameterType="int">
        delete from user where id=#{id}
    </delete>

  第二步,修改IUserDaoImpl实现类,填充deleteUserById空方法,具体代码如下:

	@Override
    public void deleteUserById(int id) {
        sqlSession.delete("test.deleteUserById",id);
        sqlSession.commit();
        this.close();
    }

  第三步,修改MyBatisTest测试类,在该类中添加测试方法TestDeleteUserById,具体代码如下所示:

	@Test
    public void TestDeleteUserById(){
        userDao.deleteUserById(10);
    }

  第四步,查看当前user数据表如下所示:
在这里插入图片描述
  第五步,运行TestDeleteUserById测试方法后,查看user数据表中,发现id为10的记录已经被删除,说明测试通过。
在这里插入图片描述
在这里插入图片描述

1.5 修改某个用户

  第一步,修改SQL映射文件,添加update标签和更新SQL语句。这里需要注意的是:由于参数为包装类型,因此这里的#{}里面的内容必须与User对象的属性名称一致,不能再随意写,具体代码如下:

	<update id="updateUser" parameterType="com.ccff.mybatis.model.User">
        update user set username=#{username} where id=#{id}
    </update>

  第二步,修改IUserDaoImpl实现类,填充updateUser空方法,具体代码如下:

	@Override
    public void updateUser(User user) {
        sqlSession.update("test.updateUser",user);
        sqlSession.commit();
        this.close();
    }

  第三步,修改MyBatisTest测试类,在该类中添加测试方法TestUpdateUser,具体代码如下所示:

	@Test
    public void TestUpdateUser(){
        User user = new User();
        user.setId(4);
        user.setUsername("王丽");
        userDao.updateUser(user);
    }

  第四步,查看当前user数据表如下所示:
在这里插入图片描述
  第五步,运行TestUpdateUser测试方法后,查看user数据表中,发现id为4的记录中username由原来的“孙丽”变为了现在的“王丽”,说明测试通过。
在这里插入图片描述
在这里插入图片描述

1.6 查询所有用户,以List形式返回

  第一步,修改SQL映射文件,添加id为“findAllUserToList”的select标签。注意,resultType属性并非指查询结果集最后的类型,而是每查出DB中的一条记录,将该记录封装成为的对象的类型。这里的resultType属性使用的是全限定性类名。

	<select id="findAllUserToList" resultType="com.ccff.mybatis.model.User">
        select * from user
    </select>

  第二步,修改IUserDaoImpl实现类,填充findAllUserToList空方法,具体代码如下:

 	@Override
    public List<User> findAllUserToList() {
        List<User> users = null;
        users = sqlSession.selectList("test.findAllUserToList");
        this.close();
        return users;
    }

  第三步,修改MyBatisTest测试类,在该类中添加测试方法TestFindAllUserToList,具体代码如下所示:

	@Test
    public void TestFindAllUserToList(){
        List<User> users = userDao.findAllUserToList();
        for (User user : users){
            System.out.println(user);
        }
    }

  第四步,查看当前user数据表如下所示:
在这里插入图片描述
  第五步,运行TestFindAllUserToList测试方法后,得到如下日志信息,且在控制台输出了全部用户信息,说明测试通过。
在这里插入图片描述

1.7 查询所有用户,以Map形式返回

  第一步,修改SQL映射文件,添加id为“findAllUserToMap”的select标签。

	<select id="findAllUserToMap" resultType="com.ccff.mybatis.model.User">
        select * from user
    </select>

  第二步,修改IUserDaoImpl实现类,填充findAllUserToMap空方法,这里使用SqlSession的selectMap方法完成查询操作。该查询方法会将查询出的每条记录先封装成指定对象,然后再将该对象作为value,将该对象的指定属性所对应的字段名作为key封装为一个Map对象。具体代码如下:

	@Override
    public Map<String, User> findAllUserToMap() {
        Map<String,User> userMap = null;
        userMap = sqlSession.selectMap("test.findAllUserToMap","username");
        this.close();
        return userMap;
    }

  第三步,修改MyBatisTest测试类,在该类中添加测试方法TestFindAllUserToMap,具体代码如下所示:

	@Test
    public void TestFindAllUserToMap(){
        Map<String,User> userMap = userDao.findAllUserToMap();
        User user = userMap.get("张三");
        System.out.println(user);
    }

  第四步,查看当前user数据表如下所示:
在这里插入图片描述
  第五步,运行TestFindAllUserToMap测试方法后,得到如下日志信息,且在控制台输出了username为“张三”的用户信息,说明测试通过。
在这里插入图片描述

1.8 根据username模糊查询某个用户

  第一步,修改SQL映射文件,添加id为“findUserByName”的select标签。具体代码如下:

	<select id="findUserByName" parameterType="String" resultType="com.ccff.mybatis.model.User">
      select * from user where username like '%' #{username} '%'
    </select>

  这种方式是以动态参数的形式出现在SQL语句中的。在进行模糊查询时,需要进行字符串的拼接,SQL语句中的字符串拼接使用的是函数concat(arg1,arg2,…)。注意,不能使用Java中的字符串连接符+。上面的SQL语句写法与下面的写法是等效的。

<select id="findUserByName" parameterType="String" resultType="com.ccff.mybatis.model.User">
      select * from user where username like concat('%',#{username},'%')
    </select>

  除此之外,还可以使用如下方式,但是需要注意,下面的${}中只能使用value,不能使用其他。而且这种方式是纯粹的字符串拼接,直接将参数拼接到了SQL语句中,也就是说这种方式可能会发生SQL注入问题。

	<select id="findUserByName" parameterType="String" resultType="com.ccff.mybatis.model.User">
      select * from user where username like '%'${value}'%'
    </select>

  第二步,修改IUserDaoImpl实现类,填充findUserByName空方法,具体代码如下:

	@Override
    public List<User> findUserByName(String username) {
        List<User> users = null;
        users = sqlSession.selectList("test.findUserByName",username);
        this.close();
        return users;
    }

  第三步,修改MyBatisTest测试类,在该类中添加测试方法TestFindUserByName,具体代码如下所示:

	@Test
    public void TestFindUserByName(){
        List<User> users = userDao.findUserByName("丽");
        for (User user : users){
            System.out.println(user);
        }
    }

  第四步,查看当前user数据表如下所示:
在这里插入图片描述
  第五步,运行TestFindUserByName测试方法后,得到如下日志信息,且在控制台输出了username中包含“丽”的用户信息,说明测试通过。
在这里插入图片描述

1.9 parameterType的别名问题

  对于一个映射文件来说,一般情况下是对一个类的操作均放在同一个映射文件。所以,一个映射文件中出现的类一般都是相同的,而每一个需要指定类名的地方均需要全限定性类名,会比较麻烦。所以,MyBatis支持为类起别名的方式。

  指定别名的第一种方式: 在全局配置文件中properties标签和setting标签后,添加typeAliases标签,指定类的别名。其中,type表示全限定性类名,alias表示别名。该方式的好处是可以指定别名为简单类型以外的其他形式。当然,弊端就是必须为每一个类逐个指定,比较繁琐。具体如下:

<?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">
<configuration>
    <properties resource="jdbc.properties" />
    
    <settings>
        <setting name="logImpl" value="LOG4J" />
    </settings>

    <typeAliases>
        <typeAlias type="com.ccff.mybatis.model.User" alias="User"/>
    </typeAliases>

    <!-- 和spring整合后 environments配置将废除-->
    <environments default="development">
        <environment id="development">
            <!-- 使用jdbc事务管理-->
            <transactionManager type="JDBC" />
            <!-- 数据库连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="sqlmap/UserMapper.xml"/>
    </mappers>
</configuration>

  指定别名的第一种方式: 对于实体类的全限定性类名的别名指定方式,一般采用package标签方式配置。这样的好处是会将该包中所有实体类的简单类名指定为别名,写法简单方便。但是弊端是只能将类的简单类名作为别名。具体配置如下:

<?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">
<configuration>
    <properties resource="jdbc.properties" />
    
    <settings>
        <setting name="logImpl" value="LOG4J" />
    </settings>

    <typeAliases>
        <!--<typeAlias type="com.ccff.mybatis.model.User" alias="User"/>-->
        <package name="com.ccff.mybatis.model"/>
    </typeAliases>

    <!-- 和spring整合后 environments配置将废除-->
    <environments default="development">
        <environment id="development">
            <!-- 使用jdbc事务管理-->
            <transactionManager type="JDBC" />
            <!-- 数据库连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="sqlmap/UserMapper.xml"/>
    </mappers>
</configuration>

  当采用第二种方式配置了别名后,之前的SQL映射文件中的全限定性类名就可以用其简单类名代替,具体修改为如下所示:

<?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="test">
    <insert id="insertUser" parameterType="User">
        insert into user (username,password,gender,email,province,city,birthday) values (#{username},#{password},#{gender},#{email},#{province},#{city},#{birthday})
        <selectKey resultType="int" keyProperty="id" order="AFTER">
            select @@identity
        </selectKey>
    </insert>
    <insert id="insertUserCatchId" parameterType="User">
        insert into user (username,password,gender,email,province,city,birthday) values (#{username},#{password},#{gender},#{email},#{province},#{city},#{birthday})
        <selectKey resultType="int" keyProperty="id" order="AFTER">
            select @@identity
        </selectKey>
    </insert>
    <delete id="deleteUserById" parameterType="int">
        delete from user where id=#{id}
    </delete>
    <update id="updateUser" parameterType="User">
        update user set username=#{username} where id=#{id}
    </update>
    <select id="findAllUserToList" resultType="User">
        select * from user
    </select>
    <select id="findAllUserToMap" resultType="User">
        select * from user
    </select>
    <select id="findUserById" parameterType="int" resultType="User">
      select * from user where id=#{id}
    </select>
    <select id="findUserByName" parameterType="String" resultType="User">
      select * from user where username like '%' #{username} '%'
    </select>
</mapper>

2、属性名与查询字段名不同

  resultType可以将查询结果直接映射为实体Bean对象的条件是:SQL查询的字段名与实体Bean的属性名已知。 因为在将查询结果转换为指定类型对象时,系统自动将查询结果字段名称作为对象的属性名,通过反射机制完成对象的创建。

  当SQL查询结果的字段名与实体Bean的属性名不一致时,将无法创建出需要类型的对象,此时有两种解决方法。

2.1 测试环境搭建

  对原有的user表中的字段名进行修改,将原有的username字段名修改为name。修改后的表结构如下图所示:
在这里插入图片描述

2.2 查询字段使用别名

  虽然属性名称与表中字段名称不一致,但可以为查询结果的字段名赋予别名,让别名与实体Bean的属性名相同。这样框架也可以根据查询结果利用反射机制将对象创建。

  假设当前需要查询id为3的用户的用户名。第一步,在SQL映射文件中修改相应的根据id查询用户信息的SQL语句,修改如下:

	<select id="findUserByIdAlias" parameterType="int" resultType="User">
    	select id,name username,password,gender,email,province,city,birthday from user where id=#{id}
    </select>

  UserDao实现类IUserDaoImpl中的具体代码如下:

	@Override
    public User findUserById(int id) {
        User user = sqlSession.selectOne("test.findUserByIdAlias",id);
        this.close();
        return  user;
    }

  测试类MyBatisTest中测试该查询的方法TestSelectByIdAlias代码如下:

	@Test
	public void TestSelectByIdAlias() {
        User user = userDao.findUserById(3);
        System.out.println(user);
    }

  运行测试方法TestSelectByIdAlias后,在控制台输出id为3的用户信息,说明测试通过。
在这里插入图片描述

2.3 使用结果映射resultMap

  可以使用结果映射resultMap(这里的Map是映射mapper的意思)来建立映射关系,完成由字段到属性的映射,达到将查询结果封装为对象的目的。 resultMap是对resultType的增强。

  修改SQL映射文件,添加resultMap映射配置如下:

	<resultMap id="userMapper" type="User">
    	<result column="name" property="username"/>
    </resultMap>
    <select id="findUserByIdAlias" parameterType="int" resultType="User" resultMap="userMapper">
    	select * from user where id=#{id}
    </select>

  其余的配置不动,再次运行测试方法TestSelectByIdAlias后,在控制台输出id为3的用户信息,说明测试通过。
在这里插入图片描述
  这里需要注意的是:在resultMap标签中,定义了由type指定的类的属性名到表中字段名称的映射关系。根据这个映射关系,框架利用反射机制创建相应的对象。

  • type:指定要映射的实体类
  • id:指定该resultMap映射关系的名称
  • < id >标签:id的字段名column与实体类的属性property间的映射关系
  • < result >标签:id以外其他字段名column与实体类的属性property间的映射关系。

  这里可以看到,对于自增id字段的映射与普通字段的映射是由区别的。对于字段名与实体类属性名相同的情况,可以不写入resultMap标签中。

猜你喜欢

转载自blog.csdn.net/weixin_36378917/article/details/84978388
今日推荐