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 定義輸出結果的類型。

 

始終相信,學習了多多少少會有收穫,不學什麼都沒有

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章