1. 程式人生 > >MyBatis學習(1):Mybatis使用詳解和入門案例

MyBatis學習(1):Mybatis使用詳解和入門案例

前言

MyBatis和Hibernate一樣,是一個優秀的持久層框架。已經說過很多次了,原生的jdbc操作存在大量的重複性程式碼(如註冊驅動,建立連線,建立statement,結果集檢測等)。框架的作用就是把這些繁瑣的程式碼封裝,這樣可以讓程式設計師專注於sql語句本身。

MyBatis通過XML或者註解的方式將要執行的sql語句配置起來,並通過java物件和sql語句對映成最終執行的sql語句。最終由MyBatis框架執行sql,並將結果對映成java物件並返回。

正文

一,MyBatis的執行流程

  1. mybatis配置檔案,包括Mybatis全域性配置檔案和Mybatis對映檔案,其中全域性配置檔案配置了資料來源、事務等資訊;對映檔案配置了SQL執行相關的
    資訊。
  2. mybatis通過讀取配置檔案資訊(全域性配置檔案和對映檔案),構造出SqlSessionFactory,即會話工廠。
  3. 通過SqlSessionFactory,可以建立SqlSession即會話。Mybatis是通過SqlSession來操作資料庫的。
  4. SqlSession本身不能直接操作資料庫,它是通過底層的Executor執行器介面來操作資料庫的。Executor介面有兩個實現類,一個是普通執行器,一個是快取執行器(預設)。
  5. Executor執行器要處理的SQL資訊是封裝到一個底層物件MappedStatement中。該物件包括:SQL語句、輸入引數對映資訊、輸出結果集對映資訊。其中輸入引數和輸出結果的對映型別包括java的簡單型別、HashMap集合物件、POJO物件型別。

二,MyBatis經典入門案例(原始DAO實現使用者表的增刪改查)

1,環境準備

  • Jdk環境:jdk1.7.0_72
  • Ide環境:eclipse indigo
  • 資料庫環境:MySQL 5.1
  • Mybatis:3.2.7

mysql建庫:

CREATE TABLE `user4` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(20) ,
  `password` varchar(20) ,
  `age` int(11) ,
  PRIMARY KEY (`id`)
)

專案目錄如下:
這裡寫圖片描述

下面一一講解這些檔案。

2,全域性配置檔案:SqlMapConfig.xml

主要是2個標籤:

  • environments-用於獲取連線池連線,將來與spring整合時,這個就不要啦,由spring來配置資料庫連線。

  • mappers-用於引用對映檔案。

<?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">
        <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/user"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="User.xml"/>
    </mappers>
</configuration>

3,建立主體類:User.class

package com.jimmy.domain;

public class User {
    private Integer id;
    private String username;
    private String password;
    private Integer age;
    //get,set方法省略
}

4,建立對映檔案:User.xml

對映檔案就是框架的核心啦,下面這個檔案就配置了java物件與資料庫表之間的對映。

我們看到,其中4個標籤:select,insert ,delete ,update 分別對應著“查,增,刪,改”操作。每個標籤中還有一些屬性,下面來解釋下:

  • id:給標籤體內的sql操作起個名字,方便呼叫。
  • parameterType:傳入引數的型別。傳入java型別,轉化為sql型別,新增到sql語句上。
  • resultType:返回結果型別。sql結果集轉化為java型別並返回。
<?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屬性,不然會報錯,可看做包名-->
<mapper namespace="user">
    <select id="findUserById" parameterType="int" resultType="com.jimmy.domain.User">
        select * from user4 where id = #{id}
    </select>
    <select id="findUserAll" resultType="com.jimmy.domain.User">
        select * from user4 
    </select>
    <insert id="insertUser" parameterType="com.jimmy.domain.User">
        insert into user4(username,password,age) values(#{username},#{password},#{age})
    </insert>
    <delete id="deleteUserById" parameterType="int">
        delete from user4 where id=#{id}
    </delete>
    <update id="updateUserPassword" parameterType="com.jimmy.domain.User">
        update user4 set password=#{password} where id=#{id}
    </update>
</mapper>

5,建立dao介面和實現類

package com.jimmy.dao;

import java.util.List;

import com.jimmy.domain.User;

// 介面
public interface UserDao {  
    public User findUserById(int id) throws Exception ;
    public List<User> findAllUsers() throws Exception;
    public void insertUser(User user) throws Exception;
    public void deleteUserById(int id) throws Exception;
    public void updateUserPassword(User user) throws Exception;
}
package com.jimmy.dao.impl;

import java.io.InputStream;
import java.util.List;

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 com.jimmy.dao.UserDao;
import com.jimmy.domain.User;

// 實現類
public class UserDaoImpl implements UserDao {

    public User findUserById(int id) throws Exception {
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();
        //---------------
        User user = session.selectOne("user.findUserById",id); //引數一:namespace.id           
        //--------------
        session.close();
        return user;
    }

    public List<User> findAllUsers() throws Exception {
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();
        //---------------------
        List<User> users = session.selectList("user.findUserAll");
        //----------------------
        session.close();
        return users;
    }

    public void insertUser(User user) throws Exception {
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();
        //---------------------
        session.insert("user.insertUser", user);
        session.commit();   //增刪改,一定一定要加上commit操作
        //----------------------
        session.close();
    }

    public void deleteUserById(int id) throws Exception {
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();
        //---------------------
        session.delete("user.deleteUserById", id);
        session.commit();   //增刪改,一定一定要加上commit操作
        //----------------------
        session.close();
    }

    public void updateUserPassword(User user) throws Exception {
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();
        //---------------------
        session.update("user.updateUserPassword", user);
        session.commit();   //增刪改,一定一定要加上commit操作
        //----------------------
        session.close();
    }
}

6,編寫測試類

package com.jimmy.test;

import java.util.List;
import org.junit.Test;
import com.jimmy.dao.UserDao;
import com.jimmy.dao.impl.UserDaoImpl;
import com.jimmy.domain.User;

public class Test3 {
    @Test
    public void testFindUserById() throws Exception{
        UserDao userDao = new UserDaoImpl();
        User user = userDao.findUserById(7);
        System.out.println(user);
    }
    @Test
    public void testFindAllUser() throws Exception{
        UserDao userDao = new UserDaoImpl();
        List<User> findAllUsers = userDao.findAllUsers();
        for (User user2 : findAllUsers) {           
            System.out.println(user2);
        }
    }
    @Test
    public void testInsertUser() throws Exception{
        UserDao userDao = new UserDaoImpl();
        User user = new User();
        user.setUsername("張三");
        user.setPassword("lalal");
        user.setAge(12);
        userDao.insertUser(user);
    }
    @Test
    public void testDeleteUserById() throws Exception{
        UserDao userDao = new UserDaoImpl();
        userDao.deleteUserById(3);
    }
    @Test
    public void testUpdateUserPassword() throws Exception{
        UserDao userDao = new UserDaoImpl();
        User user = new User();
        user.setId(9);
        user.setPassword("newpassword");
        userDao.updateUserPassword(user);
    }
}

至此,一個完整的Mybatis入門案例已經初步完成。

回過頭來看DAO的實現類,原始dao開發存在一些問題:

  • 存在一定量的模板程式碼。比如:通過SqlSessionFactory建立SqlSession;呼叫SqlSession的方法操作資料庫;關閉Sqlsession。
  • 存在一些硬編碼。呼叫SqlSession的方法操作資料庫時,需要指定statement的id,這裡存在了硬編碼。

三,Mapper代理開發模式

Mapper代理的開發方式,程式設計師只需要編寫mapper介面(相當於dao介面)即可,而不同再寫dao實現類啦。Mybatis會自動的為mapper介面生成動態代理實現類。不過要實現mapper代理的開發方式,需要遵循一些開發規範。

  1. mapper介面的全限定名要和mapper對映檔案的namespace的值相同。
  2. mapper介面的方法名稱要和mapper對映檔案中的statement的id相同。
  3. mapper介面的方法引數只能有一個,且型別要和mapper對映檔案中statement的parameterType的值保持一致。
  4. mapper介面的返回值型別要和mapper對映檔案中statement的resultType值或resultMap中的type值保持一致。

上面4句話的意思是:介面的包名,類名,引數,返回值分別對應著對映檔案的namespace,id,parameterType,resultType。

下面來改造上面的例子。

1,環境準備,同上。
2,全域性配置檔案,同上。記得引用新的對映檔案。
3,建立主題類,同上。
4,建立對映檔案:UserMapper.xml。檔名一般加上“Mapper”。

下面這個檔案跟原始dao程式設計只有一點不同,就是namespace值。

<?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屬性,不然會報錯,且mapper開發時設定為Mapper介面的全限定名-->
<mapper namespace="com.jimmy.dao.UserMapper">
    <select id="findUserById" parameterType="int" resultType="com.jimmy.domain.User">
        select * from user4 where id = #{id}
    </select>
    <select id="findUserAll" resultType="com.jimmy.domain.User">
        select * from user4 
    </select>
    <insert id="insertUser" parameterType="com.jimmy.domain.User">
        insert into user4(username,password,age) values(#{username},#{password},#{age})
    </insert>
    <delete id="deleteUserById" parameterType="int">
        delete from user4 where id=#{id}
    </delete>
    <update id="updateUserPassword" parameterType="com.jimmy.domain.User">
        update user4 set password=#{password} where id=#{id}
    </update>
</mapper>

5,建立Mapper介面,這裡就沒有實現類啦。

注意,函式一定要注意4點規範。

package com.jimmy.dao;

import java.util.List;

import com.jimmy.domain.User;

public interface UserMapper {
    public User findUserById(int id);
    public List<User> findUserAll();
    public void insertUser(User user);
    public void deleteUserById(int id);
    public void updateUserPassword(User user);
}

6,編寫測試類

package com.jimmy.test;

import java.io.InputStream;
import java.util.List;

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.Test;

import com.jimmy.dao.UserMapper;
import com.jimmy.domain.User;

public class Test1 {
    @Test
    public void findUserByID() throws Exception{
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();
        //---------------
        UserMapper userMapper = session.getMapper(UserMapper.class);
        User user = userMapper.findUserById(2);
        System.out.println(user);
        //--------------
        session.close();
    }
    @Test
    public void findAll() throws Exception{
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();
        //---------------------
        UserMapper mapper = session.getMapper(UserMapper.class);
        List<User> user = mapper.findUserAll();
        for (User user2 : user) {           
            System.out.println(user2);
        }
        //----------------------
        session.close();
    }
    @Test
    public void insertTest() throws Exception{
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();
        //---------------------
        User user = new User();
        user.setUsername("lalala");
        user.setPassword("asdf");
        user.setAge(12);

        UserMapper mapper = session.getMapper(UserMapper.class);
        mapper.insertUser(user);
        session.commit();
        //----------------------
        session.close();
    }
    @Test
    public void deleteUserById() throws Exception{
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();
        //---------------------
        UserMapper mapper = session.getMapper(UserMapper.class);
        mapper.deleteUserById(2);
        session.commit();
        //----------------------
        session.close();
    }
    @Test
    public void updateUserPassword() throws Exception{
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();
        //---------------------
        User user = new User();
        user.setId(4);
        user.setPassword("newPassword3");

        UserMapper mapper = session.getMapper(UserMapper.class);
        mapper.updateUserPassword(user);
        session.commit();
        //----------------------
        session.close();
    }
}

我們看到,現在已經不需要再寫dao介面的實現類啦,而是框架通過對映檔案為我們生成代理類。而那些重複性的程式碼已經轉移到測試程式碼中了,我們在整合spring和Mybatis時,這些重複性程式碼都會在配置檔案中配置。