1. 程式人生 > 其它 >MyBatis筆記(一)

MyBatis筆記(一)

一、MyBatis是什麼?

MyBatis是一個優秀的基於java的持久層框架,它內部封裝了JDBC,使開發者只需要關注SQL語句本身,而不需要花費精力去處理載入驅動、建立連線、建立Statement等繁雜的過程。

二、原來的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/mybatis?characterEncoding=utf-8", "root", "root");
            //定義 sql 語句 ?表示佔位符
            String sql = "select * from user where username = ?";
            //獲取預處理 statement
            preparedStatement = connection.prepareStatement(sql);
            //設定引數,第一個引數為 sql 語句中引數的序號(從 1 開始),第二個引數為設定的引數值
            preparedStatement.setString(1, "王五");
            //向資料庫發出 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) {
                    e.printStackTrace();
                }
            }
        }
    }

JDBC存在的問題:

  1. 資料庫連結建立、釋放頻繁造成系統資源浪費從而影響系統性能,如果使用資料庫連結池可解決此問題。
  2. SQL語句在程式碼中硬編碼,造成程式碼不易維護,實際應用SQL變化的可能較大,SQL變動需要改變Java程式碼。
  3. 使用PreparedStatement向佔有位符號傳引數存在硬編碼,因為SQL語句的where條件不一定,可能多也可能少,修改SQL還要修改程式碼,系統不易維護。
  4. 對結果集解析存在硬編碼(查詢列名),SQL變化導致解析程式碼變化,系統不易維護,如果能將資料庫記錄封裝成pojo物件解析比較方便。

三、MyBatis環境搭建步驟

  1. 建立Maven工程
GroupId: com.itheima
ArtifactId: mybatis01
  1. 匯入依賴座標pom.xml
    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.46</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
        </dependency>
    </dependencies>
  1. 編寫實體類com/itheima/domain/User.java
package com.itheima.domain;

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

@Data
public class User implements Serializable {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
}
  1. 編寫持久層介面com/itheima/dao/UserDao.java
package com.itheima.dao;

import com.itheima.domain.QueryVo;
import com.itheima.domain.User;
import java.util.List;

public interface UserDao {

    /**
     * 查詢所有使用者
     * @return
     */
    List<User> findAll();

    /**
     * 根據id查詢使用者
     * @param id
     * @return
     */
    User findById(Integer id);

    /**
     * 儲存使用者
     * @param user
     * @return
     */
    int saveUser(User user);

    /**
     * 更新使用者
     * @param user
     * @return
     */
    int updateUser(User user);

    /**
     * 刪除使用者
     * @param id
     * @return
     */
    int deleteUser(Integer id);

    /**
     * 根據使用者名稱模糊查詢
     * @param username
     * @return
     */
    List<User> findByName(String username);

    /**
     * 查詢使用者數量
     * @return
     */
    Integer findCount();

    /**
     * 根據QueryVo中的條件查詢使用者
     * @param vo
     * @return
     */
    List<User> findByVo(QueryVo vo);
}

  1. 編寫MyBatis配置檔案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">
<configuration>
    <typeAliases>
        <package name="com.itheima.domain"/>
    </typeAliases>

    <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/ee50"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <package name="com.itheima.dao"/>
    </mappers>

</configuration>
  1. 編寫對映配置檔案com/itheima/dao/UserDao.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.itheima.dao.UserDao">
    <select id="findAll" resultType="User">
        select * from user
    </select>
    <select id="findById" resultType="User" parameterType="int">
        select * from user where id = #{id}
    </select>
    <insert id="saveUser" parameterType="User">
        <selectKey keyColumn="id" keyProperty="id" resultType="int">
            select last_insert_id();
        </selectKey>
        insert into user(username, birthday, sex, address)
            values(#{username}, #{birthday}, #{sex}, #{address})
    </insert>
    <update id="updateUser" parameterType="User">
        update user set username=#{username}, birthday=#{birthday}, sex=#{sex},
            address=#{address} where id=#{id}
    </update>
    <delete id="deleteUser" parameterType="int">
        delete from user where id=#{id}
    </delete>

    <select id="findByName" parameterType="string" resultType="User">
        select * from user where username like #{username}
    </select>
    <select id="findCount" resultType="int">
        select count(*) from user
    </select>

    <select id="findByVo" resultType="User" parameterType="QueryVo">
        select * from user where username like #{user.username}
    </select>
</mapper>
  1. 編寫測試類com/itheima/test/MyBatisTests.java
package com.itheima.test;

import com.itheima.dao.UserDao;
import com.itheima.domain.QueryVo;
import com.itheima.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 javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;

public class MyBatisTests {

    private InputStream in ;
    private SqlSessionFactory factory;
    private SqlSession session;
    private UserDao userDao;

    // 一些共有操作
    @Before
    public void init() throws IOException{
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        factory = builder.build(in);
        session = factory.openSession();
        userDao = session.getMapper(UserDao.class);
    }

    @After
    public void destroy() throws Exception {
        session.commit();
        session.close();
        in.close();
    }


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

    @Test
    public void testSelectById() {
        User user = userDao.findById(1);
        System.out.println(user);
    }

    @Test
    public void testSaveUser() {
        User user = new User();
        user.setUsername("xxx");
        user.setBirthday(new Date());
        user.setSex("男");
        user.setAddress("china");
        int i = userDao.saveUser(user);
        System.out.println(i);
        System.out.println(user.getId());
    }

    @Test
    public void testUpdateUser() {
        User user = userDao.findById(2);
        user.setAddress("JiangSu");
        int i = userDao.updateUser(user);
        System.out.println(i);
    }

    @Test
    public void testDeleteUser() {
        int i = userDao.deleteUser(4);
        System.out.println(i);
    }

    @Test
    public void testFindByName() {
        List<User> userList = userDao.findByName("%g%");
        for (User user : userList) {
            System.out.println(user);
        }
    }

    @Test
    public void testFindCount() {
        int i = userDao.findCount();
        System.out.println(i);
    }

    @Test
    public void testFindByVo() {
        QueryVo vo = new QueryVo();
        User user = new User();
        user.setUsername("%w%");
        vo.setUser(user);
        List<User> userList = userDao.findByVo(vo);
        for (User resUser : userList) {
            System.out.println(resUser);
        }
    }
}

四、補充說明

  1. UserDao.javaUserDao.xml兩個檔案分別在java包和resources包下,其路徑必須保持一致且名字相同。
  2. UserDao.xml中的mapper的幾個屬性:namespace為對應的持久層介面UserDao.java的全限定類名,id為UserDao.java中相應的方法名,用於新增User後自動返回id屬性值。
  3. UserDao.xml中的resultType和parameterType:若是基本型別和String型別,可以直接寫類名;若是實體類,如User,則需要寫全限定類名。可以在SqlMapConfig.xml中註冊別名:
<typeAliases>
    <package name="com.itheima.domain"/>
</typeAliases>

註冊過後,該報下的實體類都可以用別名,及類名,首字母不區分大小寫。
4. 需要在SqlMapConfig.xml中配置對映器(mappers),一種比較方便的方法是設定整個包:

<mappers>
    <package name="com.itheima.dao"/>
</mappers>

要求mapper介面和mapper對映檔案包路徑一致且名字相同。
5. MyBatis也可以不編寫mapper對映檔案,可以將SQL語句寫在mapper介面中相應方法的上面,例如:

/**
* 查詢所有使用者
* @return
*/
@Select("select * from user")
List<User> findAll();

這種方式少些一個XML檔案,看著比較簡潔。但是一般工程不採用該方式,個人猜想是因為SQL和Java方法之間產生了耦合,修改維護不方便。