Mybatis(一)走進Mybatis與FisrtExample

前言

一直在使用,從未系統的總結起來。因此這裏給你們帶來的是mybatis的總結,系統你們可以對這個框架有必定的系統的學習與認識。
mybatis和Hibernate應該是如今主流的ORM框架了。
mybatis學習的步驟:
mybatis入門 --> 全局配置文件和映射文件詳解 --> 高級映射(一對一,一對多,多對多) -->延遲加載機制 -->一級緩存,
二級緩存(整合ehcache) --> spring整合mybatis --> 逆向工程java

1、Mybatis簡介

  • Mybatis是Apache的一個Java開源項目,是一個支持動態Sql語句的持久層框架。Mybatis能夠將Sql語句配置在XML文件中,避免
    將Sql語句硬編碼在Java類中。
  • MyBatis 是支持普通 SQL查詢,存儲過程和高級映射的優秀持久層框架。MyBatis 消除了幾乎全部的JDBC代碼和參數的手工設置
    以及結果集的檢索。MyBatis 使用簡單的 XML或註解用於配置和原始映射,將接口和 Java 的POJOs(Plain Ordinary Java
    Objects,普通的 Java對象)映射成數據庫中的記錄。

總結一下:mysql

  • 1)支持普通sql查詢
  • 2)高級映射
  • 3)存儲過程
  • 4)消除了幾乎全部jdbc代碼和參數的手工設置以及結果集的檢索

2、Mybatis與JDBC、Hibernate的區別

2.1 Mybatis與JDBC的區別

  • Mybatis經過參數映射方式,能夠將參數靈活的配置在SQL語句中的配置文件中,避免在Java類中配置參數(JDBC)
  • Mybatis經過輸出映射機制,將結果集的檢索自動映射成相應的Java對象,避免對結果集手工檢索(JDBC)
  • Mybatis能夠經過Xml配置文件對數據庫鏈接進行管理。

3、感覺JDBC和Mybatis

MyBatis 是來和數據庫打交道。那麼在這以前,咱們是使用 JDBC 來對數據庫進行增刪改查等一系列操做的,而咱們之因此會放棄
使用 JDBC,轉而使用 MyBatis 框架,這是爲何呢?
爲何使用Mybatis比JDBC直接鏈接方便和性能上好不少呢?spring

  • 新建Person實體類
public class Person {
    private Long pid;
    private String pname;
    public Long getPid() {
        return pid;
    }
    public void setPid(Long pid) {
        this.pid = pid;
    }
    public String getPname() {
        return pname;
    }
    public void setPname(String pname) {
        this.pname = pname;
    }
}
  • JDBC 查詢操做
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
 
import javax.swing.DebugGraphics;
 
import com.ys.bean.Person;
 
public class CRUDDao {
    //MySQL數據庫驅動
    public static String driverClass = "com.mysql.jdbc.Driver";
    //MySQL用戶名
    public static String userName = "root";
    //MySQL密碼
    public static String passWord = "654321";
    //MySQL URL
    public static String url = "jdbc:mysql://localhost:3306/study";
    //定義數據庫鏈接
    public static Connection conn = null;
    //定義聲明數據庫語句,使用 預編譯聲明 PreparedStatement提升數據庫執行性能
    public static PreparedStatement ps = null;
    //定義返回結果集
    public static ResultSet rs = null;
    /**
     * 查詢 person 表信息
     * @return:返回 person 的 list 集合
     */
    public static List<Person> readPerson(){
        List<Person> list = new ArrayList<>();
        try {
            //加載數據庫驅動
            Class.forName(driverClass);
            //獲取數據庫鏈接
            conn = DriverManager.getConnection(url, userName, passWord);
            //定義 sql 語句,?表示佔位符
            String sql = "select * from person where pname=?";
            //獲取預編譯處理的statement
            ps = conn.prepareStatement(sql);
            //設置sql語句中的參數,第一個爲sql語句中的參數的?(從1開始),第二個爲設置的參數值
            ps.setString(1, "qzy");
            //向數據庫發出 sql 語句查詢,並返回結果集
            rs = ps.executeQuery();
            while (rs.next()) {
                Person p = new Person();
                p.setPid(rs.getLong(1));
                p.setPname(rs.getString(2));
                list.add(p);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            //關閉數據庫鏈接
            if(rs!=null){
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(ps!=null){
                try {
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(conn!=null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
         
        return list;
    }
 
    public static void main(String[] args) {
        System.out.println(CRUDDao.readPerson());
    }
}
  • 分析問題
    1)問題一:數據庫鏈接,使用時就建立,使用完畢就關閉,這樣會對數據庫進行頻繁的獲取鏈接和關閉鏈接,形成數據庫資源浪費, 影響數據庫性能。 設想解決:使用數據庫鏈接池管理數據庫鏈接
    2)問題二:將 sql 語句硬編碼到程序中,若是sql語句修改了,那麼須要從新編譯 Java 代碼,不利於系統維護
    設想解決:將 sql 語句配置到 xml 文件中,即便 sql 語句變化了,咱們也不須要對 Java 代碼進行修改,從新編譯
    3)問題三:在 PreparedStatement 中設置參數,對佔位符設置值都是硬編碼在Java代碼中,不利於系統維護
     設想解決:將 sql 語句以及佔位符和參數都配置到 xml 文件中
    4)問題四:從 resultset 中遍歷結果集時,對錶的字段存在硬編碼,不利於系統維護
    設想解決:將查詢的結果集自動映射爲 Java 對象
    5)問題五:重複性代碼特別多,頻繁的 try-catch
    設想解決:將其整合到一個 try-catch 代碼塊中
    6)問題六:緩存作的不好,若是存在數據量很大的狀況下,這種方式性能特別低
    設想解決:集成緩存框架去操做數據庫
    7)問題七:sql 的移植性很差,若是換個數據庫,那麼sql 語句可能要重寫
    設想解決:在 JDBC 和 數據庫之間插入第三方框架,用第三方去生成 sql 語句,屏蔽數據庫的差別

4、基於XML的Mybatis入門實例

4.1 建立數據庫表

建立完成,隨便寫幾條數據進去。sql

4.2 建立一個Java項目,並導入相應的jar包

備註:log4j和Junit不是必須的,可是咱們爲了查看日誌以及便於測試,加入了這兩個jar包
目錄結構:
數據庫

4.3 項目中添加數據庫配置文件 mybatis-configuration.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標籤,當mybatis和spring整合以後,這個標籤是不用配置的 -->

    <!-- 能夠配置多個運行環境,可是每一個 SqlSessionFactory 實例只能選擇一個運行環境
      1、development:開發模式
       2、work:工做模式-->
    <environments default="development">
        <!--id屬性必須和上面的default同樣  -->
        <environment id="development">
            <!--事務管理器
                1、JDBC:這個配置直接簡單使用了 JDBC 的提交和回滾設置。它依賴於從數據源獲得的鏈接來管理事務範圍
                2、MANAGED:這個配置幾乎沒作什麼。它歷來不提交或回滾一個鏈接。而它會讓容器來管理事務的整個生命週期
                    好比 spring 或 JEE 應用服務器的上下文,默認狀況下,它會關閉鏈接。然而一些容器並不但願這樣,
                    所以若是你須要從鏈接中中止它,就能夠將 closeConnection 屬性設置爲 false,好比:
                    <transactionManager type="MANAGED">
                        <property name="closeConnection" value="false"/>
                    </transactionManager>
              -->
            <transactionManager type="JDBC"/>
            <!--dataSource 元素使用標準的 JDBC 數據源接口來配置 JDBC 鏈接對象源  -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/study"/>
                <property name="username" value="root"/>
                <property name="password" value="654321"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <!-- 註冊userMapper.xml文件,
        userMapper.xml位於com.lance.mybatis這個包下,因此resource寫成com/lance/mybatis/userMapper.xml-->
        <mapper resource="com/lance/mybatis/mapper/userMapper.xml"/>
    </mappers>
</configuration>

4.4 定義表對應的實體類

package com.lance.mybatis.bean;

import java.util.Date;


public class User {
    private int id;
    private String username;
    private int password;
    private String sex;
    private Date birthday;
    private String address;

    public int getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

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

    public int getPassword() {
        return password;
    }

    public void setPassword(int password) {
        this.password = password;
    }

    public String getSex() {
        return sex;
    }

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

    public Date getBirthday() {
        return birthday;
    }

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

    public String getAddress() {
        return address;
    }

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

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

4.5 定義操做 user 表的sql映射文件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.lance.mybatis.mapper.userMapper">

    <!-- 根據 id 查詢 user 表中的數據
        id:惟一標識符,此文件中的id值不能重複
        resultType:返回值類型,一條數據庫記錄也就對應實體類的一個對象
        parameterType:參數類型,也就是查詢條件的類型
   -->
    <select id="selectUserById"
            resultType="com.lance.mybatis.bean.User" parameterType="int">
        <!-- 這裏和普通的sql 查詢語句差很少,後面的 #{id}表示佔位符,裏面不必定要寫id,寫啥均可以,可是不要空着 -->
        select * from user where id = #{id}
    </select>


    <!-- 查詢 user 表的全部數據
        注意:由於是查詢全部數據,因此返回的應該是一個集合,這個集合裏面每一個元素都是User類型
     -->
    <select id="selectUserAll" resultType="com.lance.mybatis.bean.User">
        select * from user
    </select>

    <!-- 模糊查詢:根據 user 表的username字段
            下面兩種寫法均可以,可是要注意
            一、${value}裏面必需要寫value,否則會報錯
            二、${}表示拼接 sql 字符串,將接收到的參數不加任何修飾拼接在sql語句中
            三、使用${}會形成 sql 注入
     -->
    <select id="selectLikeUserName" resultType="com.lance.mybatis.bean.User" parameterType="String">
        select * from user where username like '%${value}%'
        <!-- select * from user where username like #{username} -->
    </select>

    <!-- 向 user 表插入一條數據 -->
    <insert id="insertUser" parameterType="com.lance.mybatis.bean.User">
        <!-- 將插入的數據主鍵返回到 user 對象中
             keyProperty:將查詢到的主鍵設置到parameterType 指定到對象的那個屬性
             select LAST_INSERT_ID():查詢上一次執行insert 操做返回的主鍵id值,只適用於自增主鍵
             resultType:指定 select LAST_INSERT_ID() 的結果類型
             order:AFTER,相對於 select LAST_INSERT_ID()操做的順序
         -->
        <selectKey keyProperty="id" resultType="int" order="AFTER">
            select LAST_INSERT_ID()
        </selectKey>
        insert into user(username,password,sex,birthday,address)
        value(#{username},#{password},#{sex},#{birthday},#{address})
    </insert>

    <!-- 根據 id 更新 user 表的數據 -->
    <update id="updateUserById" parameterType="com.lance.mybatis.bean.User">
        update user set username=#{username} where id=#{id}
    </update>

    <!-- 根據 id 刪除 user 表的數據 -->
    <delete id="deleteUserById" parameterType="int">
        delete from user where id=#{id}
    </delete>
</mapper>

4.6 向 mybatis-configuration.xml 配置文件中註冊 userMapper.xml 文件

4.7 測試功能類

package com.lance.mybatis.test;

import com.lance.mybatis.bean.User;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;

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

/**
 * @author lance(ZYH)
 * @function
 * @date 2018-07-07 21:10
 */
public class MybatisTest {
    SqlSession session = null;

    @Before
    public void init() {
        //定義mybatis全局配置文件
        String resource = "com/lance/mybatis/config/mybatis-configuration.xml";
        //加載 mybatis 全局配置文件
        InputStream inputStream = MybatisTest.class.getClassLoader()
                .getResourceAsStream(resource);
        //構建sqlSession的工廠
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //根據 sqlSessionFactory 產生 session
        session = sessionFactory.openSession();
    }

    //根據id查詢user表數據
    @Test
    public void getUserById() {
               /*這個字符串由 userMapper.xml 文件中 兩個部分構成
            <mapper namespace="com.lance.mybatis.userMapper"> 的 namespace 的值
            <select id="selectUserById" > id 值*/
        String statement = "com.lance.mybatis.mapper.userMapper.selectUserById";
        User user = session.selectOne(statement, 1);
        System.out.println(user);
        session.close();
    }

    //查詢全部user表全部數據
    @Test
    public void testSelectUserAll() {
        String statement = "com.lance.mybatis.mapper.userMapper.selectUserAll";
        List<User> listUser = session.selectList(statement);
        for (User user : listUser) {
            System.out.println(user);
        }

        session.close();

    }

    //模糊查詢:根據 user 表的username字段
    @Test
    public void testSelectLikeUserName(){
        String statement = "com.lance.mybatis.mapper.userMapper.selectLikeUserName";
        List<User> listUser = session.selectList(statement, "%張%");
        for(User user : listUser){
            System.out.println(user);
        }
        session.close();

    }

    //向 user 表中插入一條數據
    @Test
    public void testInsertUser(){
        String statement = "com.lance.mybatis.mapper.userMapper.insertUser";
        User user = new User();
        user.setUsername("劉美玲");
        user.setPassword(98766);
        user.setSex("女");
        user.setAddress("河南省啥子去");
        session.insert(statement, user);
        //提交插入的數據
        session.commit();
        session.close();
    }

    //根據 id 更新 user 表的數據
    @Test
    public void testUpdateUserById(){
        String statement = "com.lance.mybatis.mapper.userMapper.updateUserById";
        //若是設置的 id不存在,那麼數據庫沒有數據更改
        User user = new User();
        user.setId(4);
        user.setUsername("jim");
        session.update(statement, user);
        session.commit();
        session.close();
    }

    //根據 id 刪除 user 表的數據
    @Test
    public void testDeleteUserById(){
        String statement = "com.lance.mybatis.mapper.userMapper.deleteUserById";
        session.delete(statement,4);
        session.commit();
        session.close();
    }

}

5、總結

5.1 插入數據以後的主鍵值

1)數據庫設置主鍵自增機制
 userMapper.xml 文件中定義:apache

<!-- 向 user 表插入一條數據 -->
    <insert id="insertUser" parameterType="com.ys.po.User">
        <!-- 將插入的數據主鍵返回到 user 對象中
             keyProperty:將查詢到的主鍵設置到parameterType 指定到對象的那個屬性
             select LAST_INSERT_ID():查詢上一次執行insert 操做返回的主鍵id值,只適用於自增主鍵
             resultType:指定 select LAST_INSERT_ID() 的結果類型
             order:AFTER,相對於 select LAST_INSERT_ID()操做的順序
         -->
        <selectKey keyProperty="id" resultType="int" order="AFTER">
            select LAST_INSERT_ID()
        </selectKey>
        insert into user(username,password,sex,birthday,address)
            value(#{username},#{password},#{sex},#{birthday},#{address})
    </insert>

2)非自增主鍵機制緩存

<!-- 向 user 表插入一條數據 -->
    <insert id="insertUser" parameterType="com.ys.po.User">
        <!-- 將插入的數據主鍵返回到 user 對象中
        流程是:首先經過 select UUID()獲得主鍵值,而後設置到 user 對象的id中,在進行 insert 操做
             keyProperty:將查詢到的主鍵設置到parameterType 指定到對象的那個屬性
             select UUID():獲得主鍵的id值,注意這裏是字符串
             resultType:指定 select UUID() 的結果類型
             order:BEFORE,相對於 select UUID()操做的順序
         -->
        <selectKey keyProperty="id" resultType="String" order="BEFORE">
            select UUID()
        </selectKey>
        insert into user(id,username,passwor,sex,birthday,address)
            value(#{id},#{username},#{password},#{sex},#{birthday},#{address})
    </insert>

5.2 特殊總結

  • parameterType:指定輸入參數的類型
  • resultType:指定輸出結果的類型,在select中若是查詢結果是集合,那麼也表示集合中每一個元素的類型
  • 使用#{}:表示佔位符,用來接收輸入參數,類型能夠是簡單類型,pojo,HashMap等等
    若是接收簡單類型,#{}能夠寫成 value 或者其餘名稱
    若是接收 pojo 對象值,經過 OGNL 讀取對象中的屬性值,即屬性.屬性.屬性...的方式獲取屬性值
  • 使用${}:表示一個拼接符,會引發 sql 注入,不建議使用 用來接收輸入參數,類型能夠是簡單類型,pojo,HashMap等等 若是接收簡單類型,${}裏面只能是 value 若是接收 pojo 對象值,經過 OGNL 讀取對象中的屬性值,即屬性.屬性.屬性...的方式獲取屬性值
相關文章
相關標籤/搜索