主頁 > 後端開發 > MyBatis辟邪劍譜

MyBatis辟邪劍譜

2020-09-24 08:43:30 後端開發

一 MyBatis簡介

MyBatis是一個優秀的持久層框架 它對JDBC操作資料庫的程序進行封裝 開發者只需要關注SQL本身 而不需要花費精力去處理JDBC繁雜的程序代碼

MyBatis將要執行的各種Statement配置起來 并通過Java物件和Statement中的SQL進行映射生成最終執行的SQL陳述句 最后由MyBatis執行SQL并將結果映射成Java物件回傳

 

二 MyBatis優缺點

優點

1. 通過直接撰寫SQL陳述句 可以直接對SQL進行性能優化

2. 學習門檻低 學習成本低 只要有SQL基礎 就可以學習MyBatis 而且很容易上手

3. 由于直接撰寫SQL陳述句 所以靈活多變 代碼維護性更好

缺點

1. 不支持資料庫無關性 即資料庫發生變更 要寫多套代碼進行支持 移植性不好 比如分頁關鍵字

2. 需要撰寫結果映射

 

三 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物件型別

 

四 MyBatis初體驗

1. 新建一個Maven專案

pom.xml

<?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.hy.mybatis</groupId>
    <artifactId>mybatis-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!-- 定義依賴版本號 -->
    <properties>
        <junit.version>4.12</junit.version>
        <slf4j-log4j12.version>1.7.25</slf4j-log4j12.version>
        <mysql-connector-java.version>8.0.11</mysql-connector-java.version>
        <mybatis.version>3.4.6</mybatis.version>
    </properties>

    <!-- 管理jar版本號 -->
    <dependencyManagement>
        <dependencies>
            <!-- junit -->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
            </dependency>
            <!-- slf4j -->
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-log4j12</artifactId>
                <version>${slf4j-log4j12.version}</version>
            </dependency>
            <!-- mysql -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql-connector-java.version}</version>
            </dependency>
            <!-- mybatis -->
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>${mybatis.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!-- junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <!-- slf4j -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </dependency>
        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- 編譯 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

sql

-- 用戶表
CREATE TABLE user (
    id INT PRIMARY KEY AUTO_INCREMENT COMMENT '用戶id',
    username VARCHAR(32) COMMENT '用戶名',
    money DOUBLE COMMENT '用戶余額'
);

INSERT INTO user VALUES (1, '曹操', 8000);
INSERT INTO user VALUES (2, '孫權', 8000);
INSERT INTO user VALUES (3, '劉備', 8000);
INSERT INTO user VALUES (4, '諸葛亮', 5000);
INSERT INTO user VALUES (5, '司馬懿', 5000);
INSERT INTO user VALUES (6, '張飛', 0);
INSERT INTO user VALUES (7, '關羽', 0);
INSERT INTO user VALUES (8, '馬超', 1000);
INSERT INTO user VALUES (9, '黃忠', 1000);
INSERT INTO user VALUES (10, '趙云', 3000);

-- 訂單表
CREATE TABLE order_ (
    id INT PRIMARY KEY AUTO_INCREMENT COMMENT '訂單id',
    create_date DATETIME COMMENT '訂單創建時間',
    note VARCHAR(100) COMMENT '訂單備注',
    uid INT COMMENT '用戶id'
);
ALTER TABLE order_ ADD CONSTRAINT order_fk FOREIGN KEY (uid) REFERENCES user (id);

INSERT INTO order_ VALUES (3, '2015-02-04 13:22:35', '配送快一點!', 1);
INSERT INTO order_ VALUES (4, '2015-02-03 13:22:41', NULL, 1);
INSERT INTO order_ VALUES (5, '2015-02-12 16:13:23', NULL, 10);

-- 商品表
CREATE TABLE item (
    id INT PRIMARY KEY AUTO_INCREMENT COMMENT '商品id',
    name VARCHAR(32) COMMENT '商品名',
    price DOUBLE COMMENT '商品價格',
    detail VARCHAR(100) COMMENT '訂單描述'
);

INSERT INTO item VALUES (1, '臺式機', 3000.0, '該電腦質量非常好');
INSERT INTO item VALUES (2, '筆記本', 6000.0, '垃圾貨色');
INSERT INTO item VALUES (3, '背包', 200.0, '名牌背包');

-- 訂單商品關系表
CREATE TABLE order_detail (
    id INT PRIMARY KEY AUTO_INCREMENT COMMENT 'id',
    count INT COMMENT '購買數量',
    oid INT COMMENT '訂單id',
    iid INT COMMENT '商品id'
);
ALTER TABLE order_detail ADD CONSTRAINT order_detail_order_fk FOREIGN KEY (oid) REFERENCES order_ (id);
ALTER TABLE order_detail ADD CONSTRAINT order_detail_item_fk FOREIGN KEY (iid) REFERENCES item (id);

INSERT INTO order_detail VALUES (1, 1, 3, 1);
INSERT INTO order_detail VALUES (2, 2, 3, 2);
INSERT INTO order_detail VALUES (3, 3, 4, 3);
INSERT INTO order_detail VALUES (4, 4, 4, 2);


-- 一個用戶可以創建多個訂單 用戶表和訂單表是一對多的關系
-- 一個訂單可以包含多個商品 一個商品可以擁有多個訂單 訂單表和商品表是多對多的關系

2. 配置日志輸出 resources/log4j.properties

### 輸出到控制臺 ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### 輸出到檔案 ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=//Users/HUANGYI/Downloads/x-log.txt
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### 日志級別: fatal > error > warn > info > debug > trace ###
### 輸出到哪里: stdout|file ###
#log4j.rootLogger=info, stdout

### 輸出所有日志 ###
log4j.rootLogger=all, stdout

### 不輸出日志 ###
#log4j.rootLogger=off, stdout

3. 配置資料源 resources/database.properties

url=jdbc:mysql://localhost:3306/demo_hy?characterEncoding=utf8&useSSL=false
driverClassName=com.mysql.cj.jdbc.Driver
username=root
password=root

4. 創建物體類 com.hy.mybatis.model.User

public class User implements Serializable {

    private Integer id;
    private String username;
    private Double money;

    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 Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

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

5. 創建mapper介面 com.hy.mybatis.mapper.UserMapper

/**
 * mapper動態代理開發 MyBatis會自動為mapper介面生成動態代理實作類
 * 必須遵循四個原則
 * 1. mapper介面的全限定名要和mapper映射檔案的namespace相同
 * 2. mapper介面的方法名要和mapper映射檔案的statement#id相同
 * 3. mapper介面的方法引數只能有一個 且型別要和mapper映射檔案的statement#parameterType相同
 * 4. mapper介面的回傳值型別要和mapper映射檔案的statement#resultType或statement#resultMap#type相同
 * Created by Hy on 2020/7/29.
 */
public interface UserMapper {

    User selectUserById(Integer id);

    List<User> selectUserListByUsername(String username);

    List<User> selectUserListByMoney(Map map);

    Integer selectUserCount();

    Integer insertUser(User user);

    Integer deleteUserById(Integer id);

    Integer updateUserById(User user);
} 

6. 創建mapper映射檔案 com.hy.mybatis.mapper.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">

<!--
    #{} 表示一個占位符 可以實作preparedStatement向占位符中設定值
    #{} 可以有效防止sql注入 可以接收簡單型別值或pojo屬性值 如果parameterType傳輸單個簡單型別值 括號中可以是value或其它名稱

    ${} 表示拼接sql串 可以將parameterType傳入的內容拼接在sql中
    ${} 會引起sql注入(謹慎使用) 可以接收簡單型別值或pojo屬性值 如果parameterType傳輸單個簡單型別值 括號中只能是value
    -->
<mapper namespace="com.hy.mybatis.mapper.UserMapper">
    <!-- id: statement#id 要求在命名空間內唯一 -->
    <!-- parameterType: statement#parameterType 入參的java型別 可以填寫別名或java類的全限定名 -->
    <!-- resultType: statement#resultType 單條查詢結果對應的java型別 可以填寫別名或java類的全限定名 -->
    <select id="selectUserById" parameterType="Integer" resultType="User">
        SELECT *
        FROM user
        WHERE id = #{value}
    </select>

    <select id="selectUserListByUsername" parameterType="String" resultType="User">
        SELECT *
        FROM user
        WHERE username LIKE '%${value}%'
    </select>

    <select id="selectUserListByMoney" parameterType="HashMap" resultType="User">
        SELECT *
        FROM user
        LIMIT #{index}, #{count}
    </select>

    <select id="selectUserCount" resultType="Integer">
        SELECT COUNT(id)
        FROM user
    </select>

    <insert id="insertUser" parameterType="User">
        <!-- 插入資料成功后 回傳MySQL自增主鍵 -->
        <!-- keyProperty: 指定存放生成主鍵的屬性 -->
        <!-- resultType: 生成主鍵所對應的java型別 -->
        <!-- order: 指定該查詢主鍵sql陳述句的執行順序 相對于insert陳述句 -->
        <selectKey keyProperty="id" resultType="Integer" order="AFTER">
            SELECT LAST_INSERT_ID()
        </selectKey>
        INSERT INTO user (username, money)
        VALUES (#{username}, #{money})
    </insert>

    <delete id="deleteUserById" parameterType="Integer">
        DELETE FROM user
        WHERE id = #{value}
    </delete>

    <update id="updateUserById" parameterType="User">
        UPDATE user
        SET username = #{username}, money = #{money}
        WHERE id = #{id}
    </update>
</mapper>

7. 創建全域組態檔 resources/mybatis.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>

    <!-- 引入資料源組態檔 -->
    <properties resource="database.properties" />

    <!-- 別名 -->
    <typeAliases>
        <!-- 包指定 -->
        <package name="com.hy.mybatis.model" />
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <!-- 使用jdbc事務管理 -->
            <transactionManager type="JDBC" />
            <!-- 資料庫連接池 -->
            <dataSource type="POOLED">
                <property name="url" value="${url}" />
                <property name="driver" value="${driverClassName}" />
                <property name="username" value="${username}" />
                <property name="password" value="${password}" />
            </dataSource>
        </environment>
    </environments>

    <!-- mapper檔案位置 -->
    <mappers>
        <!-- 包指定 -->
        <package name="com.hy.mybatis.mapper" />
    </mappers>
</configuration>

8. 測驗

public class XTest {

    SqlSession mSession;

    @Before
    public void before() throws IOException {
        // 讀取組態檔
        InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
        // 創建會話工廠
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        // 創建SqlSession
        mSession = factory.openSession();
    }

    @After
    public void after() {
        if (null != mSession) mSession.close(); //關閉SqlSession
    }

    @Test
    public void test01() throws IOException {
        UserMapper mapper = mSession.getMapper(UserMapper.class);
        User user = mapper.selectUserById(1);
        System.out.println(user.toString());
    }

    @Test
    public void test02() throws IOException {
        UserMapper mapper = mSession.getMapper(UserMapper.class);
        List<User> userList = mapper.selectUserListByUsername("馬");
        for (User user : userList) {
            System.out.println(user.toString());
        }
    }

    @Test
    public void test03() throws IOException {
        int page = 1;
        int count = 5;
        int index = (page - 1) * count;
        Map<String, Integer> map = new HashMap<>();
        map.put("index", index);
        map.put("count", count);

        UserMapper mapper = mSession.getMapper(UserMapper.class);
        List<User> userList = mapper.selectUserListByMoney(map);
        for (User user : userList) {
            System.out.println(user.toString());
        }
    }

    @Test
    public void test04() throws IOException {
        UserMapper mapper = mSession.getMapper(UserMapper.class);
        Integer count = mapper.selectUserCount();
        System.out.println("count = " + count);
    }

    @Test
    public void test05() throws IOException {
        User user = new User();
        user.setUsername("貂蟬");
        user.setMoney(10.0);
        UserMapper mapper = mSession.getMapper(UserMapper.class);
        // 回傳受影響的行數
        Integer count = mapper.insertUser(user);
        System.out.println("受影響的行數 = " + count);
        // 增刪改需要提交事務
        mSession.commit();
        System.out.println("id = " + user.getId());
    }

    @Test
    public void test06() throws IOException {
        UserMapper mapper = mSession.getMapper(UserMapper.class);
        // 回傳受影響的行數
        Integer count = mapper.deleteUserById(12);
        System.out.println("受影響的行數 = " + count);
        // 增刪改需要提交事務
        mSession.commit();
    }

    @Test
    public void test07() throws IOException {
        User user = new User();
        user.setId(13);
        user.setUsername("黃蓋");
        user.setMoney(99.9);
        UserMapper mapper = mSession.getMapper(UserMapper.class);
        // 回傳受影響的行數
        Integer count = mapper.updateUserById(user);
        System.out.println("受影響的行數 = " + count);
        // 增刪改需要提交事務
        mSession.commit();
    }
}

 

五 動態SQL

<trim></trim> <if></if> <set></set> <where></where> <foreach></foreach> 使用示例

1. 創建物體類 com.hy.mybatis.model.Item

public class Item implements Serializable {

    private Integer id;
    private String name;
    private Double price;
    private String detail;

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    public String getDetail() {
        return detail;
    }

    public void setDetail(String detail) {
        this.detail = detail;
    }

    @Override
    public String toString() {
        return "Item{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", price=" + price +
                ", detail='" + detail + '\'' +
                '}';
    }
}

2. 創建mapper介面 com.hy.mybatis.mapper.ItemMapper

public interface ItemMapper {

    Integer insertItem(Item item);

    Integer updateItem(Item item);

    List<Item> selectItemListByNameAndPrice(Item item);

    List<Item> selectItemListByIdArray(int[] array);

    List<Item> selectItemListByIdList(List list);
}

3. 創建mapper映射檔案 com.hy.mybatis.mapper.ItemMapper.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.hy.mybatis.mapper.ItemMapper">

    <insert id="insertItem" parameterType="Item">
        INSERT INTO item
        <!-- <trim></trim> 里面條件都不成立 什么也不添加 -->
        <!-- <trim></trim> 里面有任意條件成立 添加前綴 后綴 去除指定的串 -->
        <!-- prefix: 前綴 -->
        <!-- suffix: 后綴 -->
        <!-- prefixOverrides: 第一個 需要去除的串 -->
        <!-- suffixOverrides: 最后一個 需要去除的串 -->
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <!-- <if></if> 判斷入參 如果條件成立 則把標簽體內的sql拼接上 -->
            <if test="null != id">
                id,
            </if>
            <if test="null != name">
                name,
            </if>
            <if test="null != price">
                price,
            </if>
            <if test="null != detail">
                detail,
            </if>
        </trim>
        <trim prefix="VALUES (" suffix=")" suffixOverrides=",">
            <if test="null != id">
                #{id},
            </if>
            <if test="null != name">
                #{name},
            </if>
            <if test="null != price">
                #{price},
            </if>
            <if test="null != detail">
                #{detail},
            </if>
        </trim>
    </insert>

    <update id="updateItem" parameterType="Item">
        UPDATE item
        <!-- <set></set> 里面條件都不成立 什么也不添加 -->
        <!-- <set></set> 里面有任意條件成立 添加SET 并去掉最后一個逗號 -->
        <set>
            <if test="null != name">
                name = #{name},
            </if>
            <if test="null != price">
                price = #{price},
            </if>
            <if test="null != detail">
                detail = #{detail},
            </if>
        </set>
        WHERE id = #{id}
    </update>

    <select id="selectItemListByNameAndPrice" parameterType="Item" resultType="Item">
        SELECT *
        FROM item
        <!-- <where></where> 里面條件都不成立 什么也不添加 -->
        <!-- <where></where> 里面有任意條件成立 添加WHERE 并去掉第一個AND或OR -->
        <where>
            <if test="null != name and '' != name">
                AND name LIKE '%${name}%'
            </if>
            <if test="null != price and '' != price">
                AND price &lt; #{price}
            </if>
        </where>
    </select>

    <select id="selectItemListByIdArray" parameterType="Integer" resultType="Item">
        SELECT *
        FROM item
        <where>
            <if test="null != array and array.length > 0">
                <!-- collection: 陣列引數名稱 如果傳入包裝類取陣列屬性名 如果直接傳入陣列只能填寫array -->
                <!-- item: 每次遍歷出來的物件 -->
                <!-- separator: 每次遍歷出來的物件 之間需要拼接的串 -->
                <!-- open: 開始遍歷時 需要拼接的串 -->
                <!-- close: 結束遍歷時 需要拼接的串 -->
                <foreach collection="array" item="value" separator="," open="AND id IN (" close=")">
                    #{value}
                </foreach>
            </if>
        </where>
    </select>

    <select id="selectItemListByIdList" parameterType="Integer" resultType="Item">
        SELECT *
        FROM item
        <where>
            <if test="null != list and list.size > 0">
                <!-- collection: 集合引數名稱 如果傳入包裝類取集合屬性名 如果直接傳入集合只能填寫list -->
                <!-- item: 每次遍歷出來的物件 -->
                <!-- separator: 每次遍歷出來的物件 之間需要拼接的串 -->
                <!-- open: 開始遍歷時 需要拼接的串 -->
                <!-- close: 結束遍歷時 需要拼接的串 -->
                <foreach collection="list" item="value" separator="," open="AND id IN (" close=")">
                    #{value}
                </foreach>
            </if>
        </where>
    </select>
</mapper>

4. 測驗

public class XTest {

    SqlSession mSession;

    @Before
    public void before() throws IOException {
        // 讀取組態檔
        InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
        // 創建會話工廠
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        // 創建SqlSession
        mSession = factory.openSession();
    }

    @After
    public void after() {
        if (null != mSession) mSession.close(); //關閉SqlSession
    }

    @Test
    public void test09() throws IOException {
        Item item = new Item();
        item.setName("自行車");
        item.setPrice(800.0);
        ItemMapper mapper = mSession.getMapper(ItemMapper.class);
        // 回傳受影響的行數
        Integer count = mapper.insertItem(item);
        System.out.println("受影響的行數 = " + count);
        // 增刪改需要提交事務
        mSession.commit();
    }

    @Test
    public void test10() throws IOException {
        Item item = new Item();
        item.setId(4);
        item.setName("H2");
        item.setPrice(400000.0);
        item.setDetail("川崎");
        ItemMapper mapper = mSession.getMapper(ItemMapper.class);
        // 回傳受影響的行數
        Integer count = mapper.updateItem(item);
        System.out.println("受影響的行數 = " + count);
        // 增刪改需要提交事務
        mSession.commit();
    }

    @Test
    public void test11() throws IOException {
        Item item = new Item();
        item.setName("包");
        item.setPrice(300.0);
        ItemMapper mapper = mSession.getMapper(ItemMapper.class);
        List<Item> itemList = mapper.selectItemListByNameAndPrice(item);
        for (Item i : itemList) {
            System.out.println(i.toString());
        }
    }

    @Test
    public void test12() throws IOException {
        int[] array = new int[]{1, 2};
        ItemMapper mapper = mSession.getMapper(ItemMapper.class);
        List<Item> itemList = mapper.selectItemListByIdArray(array);
        for (Item i : itemList) {
            System.out.println(i.toString());
        }
    }

    @Test
    public void test13() throws IOException {
        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(3);
        ItemMapper mapper = mSession.getMapper(ItemMapper.class);
        List<Item> itemList = mapper.selectItemListByIdList(list);
        for (Item i : itemList) {
            System.out.println(i.toString());
        }
    }
}

 

六 resultMap功能

1. 如果查詢出來的列名和物體類屬性名不一致 通過定義一個resultMap將列名和物體類屬性名系結

a. 創建物體類 com.hy.mybatis.model.Order

public class Order implements Serializable {

    private Integer id;
    private Date createDate;
    private String note;

    public Integer getId() {
        return id;
    }

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

    public Date getCreateDate() {
        return createDate;
    }

    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }

    @Override
    public String toString() {
        return "Order{" +
                "id=" + id +
                ", createDate=" + createDate +
                ", note='" + note + '\'' +
                '}';
    }
}

b. 創建mapper介面 com.hy.mybatis.mapper.OrderMapper

public interface OrderMapper {

    List<Order> selectOrderList();
}

c. 創建mapper映射檔案 com.hy.mybatis.mapper.OrderMapper.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.hy.mybatis.mapper.OrderMapper">

    <resultMap id="orderResultMap" type="Order">
        <id column="id" property="id" />
        <result column="create_date" property="createDate" />
        <result column="note" property="note" />
    </resultMap>

    <select id="selectOrderList" resultMap="orderResultMap">
        SELECT *
        FROM order_
    </select>
</mapper>

d. 測驗

public class XTest {

    SqlSession mSession;

    @Before
    public void before() throws IOException {
        // 讀取組態檔
        InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
        // 創建會話工廠
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        // 創建SqlSession
        mSession = factory.openSession();
    }

    @After
    public void after() {
        if (null != mSession) mSession.close(); //關閉SqlSession
    }
    
    @Test
    public void test08() throws IOException {
        OrderMapper mapper = mSession.getMapper(OrderMapper.class);
        List<Order> orderList = mapper.selectOrderList();
        for (Order order : orderList) {
            System.out.println(order.toString());
        }
    }
}

2. 一對一查詢 根據訂單id查找訂單包括用戶資訊

a. 創建物體類 com.hy.mybatis.model.OrderAndUser

public class OrderAndUser implements Serializable {

    private Integer id;
    private Date createDate;
    private String note;
    private User user;

    public Integer getId() {
        return id;
    }

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

    public Date getCreateDate() {
        return createDate;
    }

    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Override
    public String toString() {
        return "OrderAndUser{" +
                "id=" + id +
                ", createDate=" + createDate +
                ", note='" + note + '\'' +
                ", user=" + user +
                '}';
    }
}

b. 創建mapper介面 com.hy.mybatis.mapper.OrderMapper

public interface OrderMapper {

    OrderAndUser selectOrderAndUserById(Integer id);
}

c. 創建mapper映射檔案 com.hy.mybatis.mapper.OrderMapper.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.hy.mybatis.mapper.OrderMapper">

    <!-- 一對一 AS可以解決欄位名重復問題 -->
    <resultMap id="orderAndUserResultMap" type="OrderAndUser">
        <id column="id" property="id" />
        <result column="create_date" property="createDate" />
        <result column="note" property="note" />
        <!-- 關聯內部物件 -->
        <association property="user" javaType="User">
            <id column="uid" property="id" />
            <result column="uusername" property="username" />
            <result column="umoney" property="money" />
        </association>
    </resultMap>

    <select id="selectOrderAndUserById" parameterType="Integer" resultMap="orderAndUserResultMap">
        SELECT o.*, u.id AS uid, u.username AS uusername, u.money AS umoney
        FROM order_ o, user u
        WHERE o.uid = u.id
        AND o.id = #{value}
    </select>
</mapper>

d. 測驗

public class XTest {

    SqlSession mSession;

    @Before
    public void before() throws IOException {
        // 讀取組態檔
        InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
        // 創建會話工廠
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        // 創建SqlSession
        mSession = factory.openSession();
    }

    @After
    public void after() {
        if (null != mSession) mSession.close(); //關閉SqlSession
    }

    @Test
    public void test14() throws IOException {
        OrderMapper mapper = mSession.getMapper(OrderMapper.class);
        OrderAndUser orderAndUser = mapper.selectOrderAndUserById(3);
        System.out.println(orderAndUser.toString());
    }
}

3. 一對多查詢 根據訂單id查找訂單包括訂單明細資訊

a. 創建物體類 com.hy.mybatis.model.OrderDetail com.hy.mybatis.model.OrderAndOrderDetail

public class OrderDetail implements Serializable {

    private Integer id;
    private Integer count;
    private Item item;

    public Integer getId() {
        return id;
    }

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

    public Integer getCount() {
        return count;
    }

    public void setCount(Integer count) {
        this.count = count;
    }

    public Item getItem() {
        return item;
    }

    public void setItem(Item item) {
        this.item = item;
    }

    @Override
    public String toString() {
        return "OrderDetail{" +
                "id=" + id +
                ", count=" + count +
                ", item=" + item +
                '}';
    }
}
public class OrderAndOrderDetail implements Serializable {

    private Integer id;
    private Date createDate;
    private String note;
    private List<OrderDetail> orderDetailList;

    public Integer getId() {
        return id;
    }

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

    public Date getCreateDate() {
        return createDate;
    }

    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }

    public List<OrderDetail> getOrderDetailList() {
        return orderDetailList;
    }

    public void setOrderDetailList(List<OrderDetail> orderDetailList) {
        this.orderDetailList = orderDetailList;
    }

    @Override
    public String toString() {
        return "OrderAndOrderDetail{" +
                "id=" + id +
                ", createDate=" + createDate +
                ", note='" + note + '\'' +
                ", orderDetailList=" + orderDetailList +
                '}';
    }
}

b. 創建mapper介面 com.hy.mybatis.mapper.OrderMapper

public interface OrderMapper {

    OrderAndOrderDetail selectOrderAndOrderDetailById(Integer id);
}

c. 創建mapper映射檔案 com.hy.mybatis.mapper.OrderMapper.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.hy.mybatis.mapper.OrderMapper">

    <!-- 一對多 AS可以解決欄位名重復問題 -->
    <resultMap id="orderAndOrderDetailResultMap" type="OrderAndOrderDetail">
        <id column="id" property="id" />
        <result column="create_date" property="createDate" />
        <result column="note" property="note" />
        <!-- 關聯內部集合 -->
        <collection property="orderDetailList" ofType="OrderDetail">
            <id column="odid" property="id" />
            <result column="odcount" property="count" />
        </collection>
    </resultMap>

    <select id="selectOrderAndOrderDetailById" parameterType="Integer" resultMap="orderAndOrderDetailResultMap">
        SELECT o.*, od.id AS odid, od.count AS odcount
        FROM order_ o, order_detail od
        WHERE o.id = od.oid
        AND o.id = #{value}
    </select>
</mapper>

d. 測驗

public class XTest {

    SqlSession mSession;

    @Before
    public void before() throws IOException {
        // 讀取組態檔
        InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
        // 創建會話工廠
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        // 創建SqlSession
        mSession = factory.openSession();
    }

    @After
    public void after() {
        if (null != mSession) mSession.close(); //關閉SqlSession
    }

    @Test
    public void test15() throws IOException {
        OrderMapper mapper = mSession.getMapper(OrderMapper.class);
        OrderAndOrderDetail orderAndOrderDetail = mapper.selectOrderAndOrderDetailById(3);
        System.out.println(orderAndOrderDetail.toString());
    }
}

4. 多對多查詢 查詢所有用戶資訊及用戶購買的商品資訊

a. 創建物體類 com.hy.mybatis.model.UserAndOrderDetail

public class UserAndOrderDetail implements Serializable {

    private Integer id;
    private String username;
    private Double money;
    private List<OrderAndOrderDetail> orderAndOrderDetailList;

    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 Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    public List<OrderAndOrderDetail> getOrderAndOrderDetailList() {
        return orderAndOrderDetailList;
    }

    public void setOrderAndOrderDetailList(List<OrderAndOrderDetail> orderAndOrderDetailList) {
        this.orderAndOrderDetailList = orderAndOrderDetailList;
    }

    @Override
    public String toString() {
        return "UserAndOrderDetail{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", money=" + money +
                ", orderAndOrderDetailList=" + orderAndOrderDetailList +
                '}';
    }
}

b. 創建mapper介面 com.hy.mybatis.mapper.UserMapper

public interface UserMapper {

    List<UserAndOrderDetail> selectUserAndOrderDetail();
}

c. 創建mapper映射檔案 com.hy.mybatis.mapper.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.hy.mybatis.mapper.UserMapper">
    <!-- 多對多 AS可以解決欄位名重復問題 -->
    <resultMap id="userAndOrderDetailResultMap" type="UserAndOrderDetail">
        <id column="id" property="id" />
        <result column="username" property="username" />
        <result column="money" property="money" />

        <!-- 關聯內部集合 -->
        <collection property="orderAndOrderDetailList" ofType="OrderAndOrderDetail">
            <id column="o0" property="id" />
            <result column="o1" property="createDate" />
            <result column="o2" property="note" />

            <!-- 關聯內部集合 -->
            <collection property="orderDetailList" ofType="OrderDetail">
                <id column="od0" property="id" />
                <result column="od1" property="count" />

                <!-- 關聯內部物件 -->
                <association property="item" javaType="Item">
                    <id column="i0" property="id" />
                    <result column="i1" property="name" />
                    <result column="i2" property="price" />
                    <result column="i3" property="detail" />
                </association>
            </collection>
        </collection>
    </resultMap>

    <select id="selectUserAndOrderDetail" resultMap="userAndOrderDetailResultMap">
        SELECT u.*, o.id o0, o.create_date o1, o.note o2, od.id od0, od.count od1, i.id i0, i.name i1, i.price i2, i.detail i3
        FROM user u, order_ o, order_detail od, item i
        WHERE u.id = o.uid
        AND o.id = od.oid
        AND od.iid = i.id;
    </select>
</mapper>

d. 測驗

public class XTest {

    SqlSession mSession;

    @Before
    public void before() throws IOException {
        // 讀取組態檔
        InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
        // 創建會話工廠
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        // 創建SqlSession
        mSession = factory.openSession();
    }

    @After
    public void after() {
        if (null != mSession) mSession.close(); //關閉SqlSession
    }

    @Test
    public void test16() throws IOException {
        UserMapper mapper = mSession.getMapper(UserMapper.class);
        List<UserAndOrderDetail> userAndOrderDetailList = mapper.selectUserAndOrderDetail();
        for (UserAndOrderDetail detail : userAndOrderDetailList) {
            System.out.println(detail.toString());
        }
    }
}

 

七 MyBatis快取

和大多數的持久化框架一樣 MyBatis也提供了快取策略 通過快取策略來減少資料庫的查詢次數 從而提高性能 MyBatis中快取分為一級快取 二級快取

1. 一級快取

默認開啟

一級快取是SqlSession級別的快取 當呼叫SqlSession的增刪改等方法時 就會清空一級快取

第一次發起查詢用戶id為1的用戶資訊 先去找快取中是否有id為1的用戶資訊 如果沒有 從資料庫查詢用戶資訊 得到用戶資訊 將用戶資訊存盤到一級快取中

如果SqlSession去執行增刪改 清空SqlSession中的一級快取 這樣做可以讓快取中存盤的是最新資訊 避免臟讀

第二次發起查詢用戶id為1的用戶資訊 先去找快取中是否有id為1的用戶資訊 快取中有 直接從快取中獲取用戶資訊

2. 二級快取

需要手動開啟

二級快取是Mapper級別的快取 同一個Mapper下 多個SqlSession可以共用二級快取 當呼叫其中某個SqlSession的增刪改等方法時 就會清空二級快取

SqlSession1去查詢用戶資訊 查詢到用戶資訊會將查詢資料存盤到二級快取中

如果SqlSession3去執行增刪改 將會清空該Mapper映射下的二級快取區域的資料 這樣做可以讓快取中存盤的是最新資訊 避免臟讀

SqlSession2去查詢與SqlSession1相同的用戶資訊 首先會去快取中找是否存在資料 如果存在直接從快取中取出資料

二級快取的開啟與關閉

a. resources/mybatis.xml <properties/>節點和<typeAliases/>節點之間配置

<settings>
    <!-- 開啟二級快取 -->
    <setting name="cacheEnabled" value="true" />
</settings>

b. 配置相關的mapper映射檔案

<?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.hy.mybatis.mapper.UserMapper">

    <!-- 開啟二級快取 -->
    <cache></cache>

    <!-- useCache: true=使用二級快取 false=禁用二級緩 -->
    <select id="selectUserById" parameterType="Integer" resultType="User" useCache="true">
        SELECT *
        FROM user
        WHERE id = #{value}
    </select>

    <select id="selectUserListByUsername" parameterType="String" resultType="User">
        SELECT *
        FROM user
        WHERE username LIKE '%${value}%'
    </select>
</mapper>

二級快取的注意事項

a. 使用二級快取時 所快取的類一定要實作java.io.Serializable介面 這種就可以使用序列化方式來保存物件

b. 默認的二級快取不支持分布式

c. 二級快取對細粒度的資料 快取實作不好 比如對商品資訊進行快取 由于商品資訊訪問量大 但是要求用戶每次查詢都是最新的商品資訊 此時如果使用二級快取 就無法實作當一個商品發生變化只重繪該商品快取資訊而不重繪其他商品快取資訊 因為二級快取是Mapper級別 當一個商品資訊更新 所有的商品資訊快取資料都會清空 解決此類問題 需要在業務層根據需要對資料有針對性的快取

 

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/117766.html

標籤:Java

上一篇:探討Netty獲取并檢查Websocket握手請求的兩種方式

下一篇:SpringBoot學習之整合Mybatis

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more