Mybatis入门,通过代理对象实现CRUD快速理解

1、MyBatis 框架 概述

mybatis是一个持久层框架,用java编写的。它封装了jdbc操作的很多细节,使开发者只需要关注sql语句本身,而无需关注注册驱动,创建连接等繁杂过程 ​。它使用了ORM思想实现了结果集的封装:

Object Relational Mappging 对象关系映射, 简单的说: 就是把数据库表和实体类及实体类的属性对应起来,我们操作实体类就实现操作数据库表。


下面我们通过mybatis简单案例:对用户表User的crud操作:

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) NOT NULL COMMENT '用户名称',
  `birthday` datetime DEFAULT NULL COMMENT '生日',
  `sex` char(1) DEFAULT NULL COMMENT '性别',
  `address` varchar(256) DEFAULT NULL COMMENT '地址',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=55 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', 'Mrjie', '2020-03-27 15:50:45', '男', '永州市蓝山县');
INSERT INTO `user` VALUES ('2', 'Mary', '2020-03-27 11:44:00', '女', '北京');

 

第一步:创建 maven 工程


 

第二步:导入坐标pop.xml: 分别是mybatis、mysql、Junit依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.xiaojie</groupId>
    <artifactId>mybaits03_crud</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.3</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.46</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>
</project>


第三步:编写必要代码(实体类和持久层接口)

实体类   User.java

package com.xiaojie.pojo;

import java.io.Serializable;
import java.util.Date;

/**
 * @program: mybatis
 * @description: 用户实体类
 * @author: Mr.Li
 * @create: 2020-03-25 15:04
 **/
public class User implements Serializable {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUserName() {
        return username;
    }

    public void setUserName(String userName) {
        this.username = userName;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", userName='" + username + '\'' +
                ", birthday=" + birthday +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

持久层接口       UserDao.java

package com.xiaojie.dao;

import com.xiaojie.pojo.User;
import org.apache.ibatis.annotations.Select;

import java.util.List;

/**
 * @program: mybatis
 * @description: 用户持久层接口
 * @author: Mr.Li
 * @create: 2020-03-25 15:08
 **/
public interface UserDao {
    /**
     * 查询所有用户列表
     * @return
     */
    //@Select("select * from user")
    List<User> findAll();

    /**
     * 保存user
     * @param user
     */
    void saveUser(User user);

    /**
     * 修改user
     * @param user
     */
    void updateUser(User user);

    /**
     * 根据id删除
     * @param id
     */
    void deleteUser(Integer id);

    /**
     * 根据id查找
     * @param id
     * @return
     */
    User findUserById(Integer id);

    /**
     * 根据name 模糊查询
     * @param username
     * @return
     */
    List<User> findUserByName(String username);

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


第四步:编写 SqlConfig.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">
<configuration>
    <environments default="development">
        <!--配置mysql-->
        <environment id="development">
            <!--配置事务类型-->
            <transactionManager type="JDBC"/>
            <!--配置数据源(连接池)-->
            <dataSource type="POOLED">
                <!--连接数据库的四个基本信息-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/test_mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <!--指定映射配置文件的位置-->
    <!--xml配置 扫描的是resources配置的xml-->
    <mappers>
        <mapper resource="com/xiaojie/dao/UserMapper.xml"/>
    </mappers>

    <!--基于注解的配置,直接加载类接口
    <mappers>
        <mapper class="com.xiaojie.dao.UserDao"/>
    </mappers>-->
</configuration>


第五步:编写映射配置文件  UserMapper.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="com.xiaojie.dao.UserDao">
    <!--查询所有-->
    <select id="findAll" resultType="com.xiaojie.pojo.User">
        select * from user;
    </select>

    <!--保存user-->
    <insert id="saveUser" parameterType="com.xiaojie.pojo.User">
        <selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
            select last_insert_id();
        </selectKey>
        insert into user (username,birthday,sex,address) values(#{username},#{birthday},
          #{sex},#{address});
    </insert>

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

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

    <!--根据id查询user-->
    <select id="findUserById" parameterType="int" resultType="com.xiaojie.pojo.User">
        select * from user where id = #{id}
    </select>


    <!--根据id查询user-->
    <select id="findUserByName" parameterType="String" resultType="com.xiaojie.pojo.User">
        select * from user where username like #{username}
    </select>

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


第六步:编写测试类 ,此项目是使用Junit依赖测试

package com.xiaojie.test;

import com.xiaojie.dao.UserDao;
import com.xiaojie.pojo.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;

/**
 * @program: mybaits03_crud
 * @description: 测试mybatis的crud
 * @author: Mr.Li
 * @create: 2020-03-27 15:14
 **/
public class MybatisTest {
    private InputStream in;
    private SqlSession session;
    private UserDao userDao;

    @Before   //表示在测试方法执行之前执行,因为每个测试方法都有用到,所以将其提出共有
    public void init() throws Exception{
        //1、读取配置文件
        in = Resources.getResourceAsStream("sqlConfig.xml");
        //2、创建SqlSessionFactory
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(in);
        //3、使用工厂产生SqlSession
       session = factory.openSession();
        //4、使用SqlSession创建接口代理对象
       userDao = session.getMapper(UserDao.class);

    }

    @After   //表示在测试方法执行之后执行
    public void destroy() throws Exception{
        //提交事务
        session.commit();
        //6、释放资源
        session.close();
        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.setAddress("美国加州");
        user.setBirthday(new Date());
        user.setSex("女");
        user.setUserName("jones");

        System.out.println("保存前:" + user);
        //使用代理对象执行保存方法
        userDao.saveUser(user);
        System.out.println("保存后:" + user);
    }

    /**
     * 测试更新操作
     */
    @Test
    public void testUpdate(){
        User user = new User();
        user.setAddress("永州市蓝山县");
        user.setBirthday(new Date());
        user.setSex("男");
        user.setUserName("Mrjie");
        user.setId(41);
        //使用代理对象执行更新方法
        userDao.updateUser(user);
    }

    /**
     * 测试删除操作
     */
    @Test
    public void testDelete(){
        //使用代理对象执行删除方法
        userDao.deleteUser(53);
    }

    /**
     * 测试根据id查询操作
     */
    @Test
    public void testFindById(){
        //使用代理对象执行删除方法
        User user = userDao.findUserById(41);
        System.out.println(user);
    }

    /**
     * 测试根据username查询操作
     */
    @Test
    public void testFindByName(){
        //使用代理对象执行删除方法
        List<User> users = userDao.findUserByName("%Mr%");
        for(User user : users) {
            System.out.println(user);
        }
    }

    /**
     * 测试总记录数
     */
    @Test
    public void testFindTotal(){
       int sum = userDao.findTotal();
        System.out.println(sum);
    }
}

 

最后总结一下注意事项:

          1、持久层接口和持久层接口的映射配置必须在相同的包下


          2、持久层映射配置中 mapper 标签的 namespace 属性取值必须是持久层接口的全限定类名

           <mapper namespace="com.xiaojie.dao.UserDao">


          3、SQL 语句的配置标签<select>,<insert>,<delete>,<update>的 id 属性必须和持久层接口的方法名相同。

 

 

2、与传统JDBC编程的比较

jdbc 的原始方法(未经封装)实现了查询数据库表记录的操作。

public static void main(String[] args) {
    Connection connection = null;
    PreparedStatement preparedStatement = null;
    ResultSet resultSet = null;
    try {
        //加载数据库驱动
        Class.forName("com.mysql.jdbc.Driver");
        //通过驱动管理类获取数据库链接
        connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test_mybatis","root", "123456");
        //定义 sql 语句 ?表示占位符
        String sql = "select * from user where username = ?";
        //获取预处理 statement
        preparedStatement = connection.prepareStatement(sql);
        //设置参数,第一个参数为 sql 语句中参数的序号(从 1 开始),第二个参数为设置的参数值
        preparedStatement.setString(1, "Mrli");
        //向数据库发出 sql 执行查询,查询出结果集
        resultSet = preparedStatement.executeQuery();
        //遍历查询结果集
        while(resultSet.next()){
          System.out.println(resultSet.getString("id")+""+resultSet.getString("username"));
    	}
    } catch (Exception e) {
    	e.printStackTrace();
    }finally{
        //释放资源
        if(resultSet!=null){
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(preparedStatement!=null){
            try {
                preparedStatement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(connection!=null){
            try {
                connection.close();
            } catch (SQLException e) {
            // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

通过传统jdbc编程实现,可以看出:

1. 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
2. Sql 语句在代码中硬编码,造成代码不易维护,实际应用 sql 变化的可能较大,sql 变动需要改变 java代码。
3. 使用 preparedStatement 向占有位符号传参数存在硬编码,因为 sql 语句的 where 条件不一定,可能多也可能少,修改 sql 还要修改代码,系统不易维护。
4. 对结果集解析存在硬编码(查询列名),sql 变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成 pojo 对象解析比较方便。

最后通过jdbc的比较,可以总结出mybatis的优点:

  1. 使开发者只需要关注sql语句本身,而无需关注注册驱动,创建连接等繁杂过程
  2. 易于学习,易于使用
  3. 在 SqlMapConfig.xml 中配置数据链接池,使用连接池管理数据库链接。
  4. Mybatis自动将 sql执行结果映射至 java 对象,通过 statement 中的 resultType 定义输出结果的类型。

始终相信,学习了多多少少会有收获,不学什么都没有

猜你喜欢

转载自blog.csdn.net/qq_41216743/article/details/105150821