20 - Mybatis學習(1)-入門案例

1 MyBatis簡介

  • MyBatis 本是apache的一個開源項目iBatis, 2010年這個項目由apache software foundation 遷移到了google code,並且改名爲MyBatis,實質上Mybatis對ibatis進行一些改進。
  • MyBatis是一個優秀的持久層框架,它對jdbc的操作數據庫的過程進行封裝,使開發者只需要關注 SQL 本身,而不需要花費精力去處理例如註冊驅動、創建connection、創建statement、手動設置參數、結果集檢索等jdbc繁雜的過程代碼。
  • 對jdbc的封裝框架有哪些:Hibernate,dbutils,jdbcTemplate[spring],mybatis
  • 原理:Mybatis通過xml或註解的方式將要執行的各種statement(statement、preparedStatemnt、CallableStatement)配置起來,並通過java對象和statement中的sql進行映射生成最終執行的sql語句,最後由mybatis框架執行sql並將結果映射成java對象並返回。

1.1 MyBatis的框架核心

  1. mybatis配置文件,包括Mybatis全局配置文件和Mybatis映射文件,其中全局配置文件配置了數據源、事務等信息;映射文件配置了SQL執行相關的 信息。
  2. mybatis通過讀取配置文件信息(全局配置文件和映射文件),構造出SqlSessionFactory,即會話工廠。
  3. 通過SqlSessionFactory,可以創建SqlSession即會話。Mybatis是通過SqlSession來操作數據庫的。
  4. SqlSession本身不能直接操作數據庫,它是通過底層的Executor執行器接口來操作數據庫的。Executor接口有兩個實現類,一個是普通執行器,一個是緩存執行器(默認)。
  5. Executor執行器要處理的SQL信息是封裝到一個底層對象MappedStatement中。該對象包括:SQL語句、輸入參數映射信息、輸出結果集映射信息。其中輸入參數和輸出結果的映射類型包括HashMap集合對象、POJO對象類型。

2 Mybatis 案例

2.1 環境搭建

  • 新建數據庫,添加表
/*
SQLyog v10.2 
MySQL - 5.1.72-community : Database - mybatis
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
/*Table structure for table `items` */

CREATE TABLE `items` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL COMMENT '商品名稱',
  `price` float(10,1) NOT NULL COMMENT '商品定價',
  `detail` text COMMENT '商品描述',
  `pic` varchar(64) DEFAULT NULL COMMENT '商品圖片',
  `createtime` datetime NOT NULL COMMENT '生產日期',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

/*Table structure for table `orderdetail` */

CREATE TABLE `orderdetail` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `orders_id` int(11) NOT NULL COMMENT '訂單id',
  `items_id` int(11) NOT NULL COMMENT '商品id',
  `items_num` int(11) DEFAULT NULL COMMENT '商品購買數量',
  PRIMARY KEY (`id`),
  KEY `FK_orderdetail_1` (`orders_id`),
  KEY `FK_orderdetail_2` (`items_id`),
  CONSTRAINT `FK_orderdetail_1` FOREIGN KEY (`orders_id`) REFERENCES `orders` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `FK_orderdetail_2` FOREIGN KEY (`items_id`) REFERENCES `items` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

/*Table structure for table `orders` */

CREATE TABLE `orders` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL COMMENT '下單用戶id',
  `number` varchar(32) NOT NULL COMMENT '訂單號',
  `createtime` datetime NOT NULL COMMENT '創建訂單時間',
  `note` varchar(100) DEFAULT NULL COMMENT '備註',
  PRIMARY KEY (`id`),
  KEY `FK_orders_1` (`user_id`),
  CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

/*Table structure for table `user` */

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) NOT NULL COMMENT '用戶名稱',
  `birthday` date DEFAULT NULL COMMENT '生日',
  `sex` char(1) DEFAULT NULL COMMENT '性別',
  `address` varchar(256) DEFAULT NULL COMMENT '地址',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

添加數據
在這裏插入圖片描述

/*
SQLyog v10.2 
MySQL - 5.1.72-community : Database - mybatis
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
/*Data for the table `items` */

insert  into `items`(`id`,`name`,`price`,`detail`,`pic`,`createtime`) values (1,'臺式機',3000.0,'該電腦質量非常好!!!!',NULL,'2015-02-03 13:22:53'),(2,'筆記本',6000.0,'筆記本性能好,質量好!!!!!',NULL,'2015-02-09 13:22:57'),(3,'揹包',200.0,'名牌揹包,容量大質量好!!!!',NULL,'2015-02-06 13:23:02');

/*Data for the table `orderdetail` */

insert  into `orderdetail`(`id`,`orders_id`,`items_id`,`items_num`) values (1,3,1,1),(2,3,2,3),(3,4,3,4),(4,4,2,3);

/*Data for the table `orders` */

insert  into `orders`(`id`,`user_id`,`number`,`createtime`,`note`) values (3,1,'1000010','2015-02-04 13:22:35',NULL),(4,1,'1000011','2015-02-03 13:22:41',NULL),(5,10,'1000012','2015-02-12 16:13:23',NULL);

/*Data for the table `user` */

insert  into `user`(`id`,`username`,`birthday`,`sex`,`address`) values (1,'王五',NULL,'2',NULL),(10,'張三','2014-07-10','1','北京市'),(16,'張小明',NULL,'1','河南鄭州'),(22,'陳小明',NULL,'1','河南鄭州'),(24,'張三丰',NULL,'1','河南鄭州'),(25,'陳小明',NULL,'1','河南鄭州'),(26,'王五',NULL,NULL,NULL);

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

2.2 導入jar

在這裏插入圖片描述

2.3 添加log4j.properties

  • Mybatis使用的日誌包是log4j的,所以需要添加log4j.properties。
  • 在classpath下創建log4j.properties如下:【文件內容可以從mybatis-3.2.7.pdf中拷貝】
  • 日誌級別在開發階段設置成DEBUG,在生產階段設置成INFO或者ERROR

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

2.4 開發步驟

  1. 創建PO(model)類,根據需求創建;
  2. 創建全局配置文件SqlMapConfig.xml;
  3. 編寫映射文件;
  4. 加載映射文件,在SqlMapConfig.xml中進行加載;
  5. 編寫測試程序,即編寫Java代碼,連接並操作數據庫。

思路:
6. 讀取配置文件;
7. 通過SqlSessionFactoryBuilder創建SqlSessionFactory會話工廠。
8. 通過SqlSessionFactory創建SqlSession。
9. 調用SqlSession的操作數據庫方法。
10. 關閉SqlSession。

2.4.1 創建 PO 類

package com.tzb.model;

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


public class User implements Serializable {
	private int id;
	private String username;// 用戶姓名
	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 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 + ", sex=" + sex
				+ ", birthday=" + birthday + ", address=" + address + "]";
	}

}

2.4.2 創建 SqlMapConfig.xml

在classpath(src)下,創建SqlMapConfig.xml文件【SqlMapConfig.xml(文件頭可以從mybatis-3.2.7.pdf文檔的2.1.2小節中拷貝)】

<?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>
    <!-- 配置mybatis的環境信息 -->
    <environments default="development">
        <environment id="development">
            <!-- 配置JDBC事務控制,由mybatis進行管理 -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 配置數據源,採用dbcp連接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis_test?useUnicode=true&amp;characterEncoding=utf8"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
</configuration>

2.4.3 映射文件

在classpath下,創建sqlmap文件夾。在sqlmap目錄下,創建User.xml映射文件。
【Mybatis的映射文件頭(可以從mybatis-3.2.7.pdf文件中拷貝)】


<?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">
<!--
	namespace:命名空間,它的作用就是對SQL進行分類化管理,可以理解爲SQL隔離
	注意:使用mapper代理開發時,namespace有特殊且重要的作用
 -->
<mapper namespace="test">
    <!--
        [id]:statement的id,要求在命名空間內唯一
        [parameterType]:入參的java類型
        [resultType]:查詢出的單條結果集對應的java類型
        [#{}]: 表示一個佔位符?
        [#{id}]:表示該佔位符待接收參數的名稱爲id。注意:如果參數爲簡單類型時,#{}裏面的參數名稱可以是任意定義
     -->
    <select id="findUserById" parameterType="int" resultType="com.tzb.model.User">
		SELECT * FROM USER WHERE id = #{id}
	</select>
</mapper>

2.4.4 配置文件加載映射文件

在這裏插入圖片描述


  • 測試類
import com.tzb.model.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.Test;

import java.io.IOException;
import java.io.InputStream;

public class Demo1 {

    @Test
    public void test1() throws IOException {
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);

        SqlSession session = factory.openSession();

        User user = session.selectOne("findUserById", 10);

        System.out.println(user);

        session.close();
    }
}


3 案例

3.1 模糊查詢

  • User.xml
<!--
		[${}]:表示拼接SQL字符串
	 	[${value}]:表示要拼接的是簡單類型參數。
		 注意:
		1、如果參數爲簡單類型時,${}裏面的參數名稱必須爲value
		2、${}會引起SQL注入,一般情況下不推薦使用。但是有些場景必須使用${},比如order by ${colname}
	-->
    <select id="findUserByName" parameterType="String" resultType="com.tzb.model.User">
		SELECT * FROM USER WHERE username LIKE '%${value}%'
	</select>

  • 測試類
@Test
    public void test1() throws IOException {
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);

        SqlSession session = factory.openSession();

        /*User user = session.selectOne("findUserById", 10);
        System.out.println(user);*/

        List<User> users = session.selectList("findUserByName", "張");
        System.out.println(users);

        session.close();
    }
DEBUG [main] - Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 964635168.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.Connection@397f2a20]
DEBUG [main] - ==>  Preparing: SELECT * FROM USER WHERE username LIKE '%張%' 
DEBUG [main] - ==> Parameters: 
DEBUG [main] - <==      Total: 3
[User [id=10, username=張三, sex=1, birthday=Thu Jul 10 00:00:00 CST 2014, address=北京市], User [id=16, username=張小明, sex=1, birthday=null, address=河南鄭州], User [id=24, username=張三丰, sex=1, birthday=null, address=河南鄭州]]
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.Connection@397f2a20]
DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.Connection@397f2a20]
DEBUG [main] - Returned connection 964635168 to pool.

Process finished with exit code 0

3.2 用戶插入

  • User.xml
<!--
		這裏的佔位寫模型的屬性
	-->
	<insert id="insertUser" parameterType="com.tzb.model.User">
		INSERT INTO user (username,sex,birthday,address) VALUE (#{username},#{sex},#{birthday},#{address});
	</insert>

  • 測試類
import com.tzb.model.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.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;

public class Demo1 {

    private SqlSession session;

    @Before
    public void before() throws IOException {
        System.out.println("before.......獲取 session");
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        session = factory.openSession();
    }

    @After
    public void after() {
        System.out.println("after.......關閉 session");
        session.close();
    }

    @Test
    public void test1() throws IOException {
        User user = new User("Jenny", "1", new Date(), "上海");
        int row = session.insert("insertUser", user);

        session.commit();
        System.out.println("受影響的行數:" + row);
    }
}

在這裏插入圖片描述

3.3 刪除

  • User.xml
<!--刪除-->
	<delete id="deleteUser" parameterType="int">
		delete From user where id=#{id};
	</delete>

 @Test
    public void test2() throws IOException {
        int row = session.delete("deleteUser", 30);
        session.commit();
        System.out.println("受影響的行數:" + row);
    }

3.4 更新

在這裏插入圖片描述

  • User.xml
<!--更新-->
    <delete id="updateUser" parameterType="com.tzb.model.User">
		UPDATE user SET sex=#{sex},address=#{address}
		WHERE id=#{id};
	</delete>
 /*更新*/
    @Test
    public void test3() throws IOException {
        User user = new User();
        user.setId(31);
        user.setSex("男");
        user.setAddress("天津");

        int row = session.update("updateUser", user);
        session.commit();
        System.out.println("受影響的行數:" + row);
    }

3.5 插入後自動返回主鍵

  • MySQL自增主鍵,是指在insert之前MySQL會自動生成一個自增的主鍵。
  • 我們可以通過MySQL的函數獲取到剛插入的自增主鍵:
    LAST_INSERT_ID()
  • 這個函數是在insert語句之後去調用。

  • User.xml
<!--插入時自動返回主鍵id-->
	<insert id="insertUser2" parameterType="com.tzb.model.User">
		<!--
                    [selectKey標籤]:通過select查詢來生成主鍵
                    [keyProperty]:指定存放生成主鍵的屬性
                    [resultType]:生成主鍵所對應的Java類型
                    [order]:指定該查詢主鍵SQL語句的執行順序,相對於insert語句
                    [last_insert_id]:MySQL的函數,要配合insert語句一起使用 -->
		<selectKey keyProperty="id" resultType="int" order="AFTER">
			SELECT LAST_INSERT_ID()
		</selectKey>
		INSERT INTO user (username,sex,birthday,address)
		VALUE (#{username},#{sex},#{birthday},#{address});
	</insert>
  @Test
    public void test4() throws IOException {
        User user = new User("Jenny", "1", new Date(), "上海");
        int row = session.insert("insertUser2", user);
        session.commit();
        System.out.println("受影響的行數:" + row);
        System.out.println("用戶的ID:" + user.getId());
    }

在這裏插入圖片描述
在這裏插入圖片描述

4 總結

4.1 parameterTyperesultType

parameterType指定輸入參數的java類型,可以填寫別名或Java類的全限定名。
resultType指定輸出結果的java類型,可以填寫別名或Java類的全限定名。

4.2 #{}${}

  • #{}:相當於預處理中的佔位符?。
  • #{}裏面的參數表示接收java輸入參數的名稱。
  • #{}可以接受HashMap、POJO類型的參數。
    當接受簡單類型的參數時,#{}裏面可以是value,也可以是其他。
  • #{}可以防止SQL注入。
    -${}:相當於拼接SQL串,對傳入的值不做任何解釋的原樣輸出。
  • ${}會引起SQL注入,所以要謹慎使用。
  • ${}可以接受HashMap、POJO類型的參數。
    當接受簡單類型的參數時,${}裏面只能是value。

4.3 selectOneselectList

selectOne:只能查詢0或1條記錄,大於1條記錄的話,會報錯:
selectList:可以查詢0或N條記錄

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