MyBatis 級聯查詢與逆向工程

一、物理外鍵

1.1 外鍵的理解

外鍵是建立在從表的一個字段(通常是專門新建的字段)指向主表的一個字段(通常是被設爲主鍵的一個字段)的引用,用於強調和約束兩個表的主從關係。

1.2 外鍵的選擇

一對一

一般一對一關係的表存在明顯的主從關係,一般在從表中新建一個用於保存關係的字段,並建立由字段指向主表主鍵的外鍵。

一對多、多對一

一般在一對多、多對一關係的表中,一般在表示關係的表中新建用於保存關係的字段,並建立由該字段指向表示關係的表主鍵的外鍵。

多對多

一般需要新建一張中間表用於保存關係,有兩個字段並建立分別由這兩個字段指向表示關係的表主鍵的外鍵,並且一般設這兩個字段爲主鍵(聯合主鍵)。

1.3 外鍵優缺點

外鍵的存在保證了數據的強一致性,表關係一目瞭然而且級聯操作非常方便。但是在INSERTUPDATEDELETE等操作時等都會先檢查外鍵的約束條件再操作,性能有所下降。

阿里巴巴的MySQL規約中強制禁用物理外鍵。因此通常情況下都用中間表來存儲表的關係,由應用層維護數據的一致性。

【強制】不得使用外鍵與級聯,一切外鍵概念必須在應用層解決。 說明:以學生和成績的關係爲例,學生表中的student_id是主鍵,那麼成績表中的student_id則爲外鍵。如果更新學生表中的student_id,同時觸發成績表中的student_id更新,即爲級聯更新。外鍵與級聯更新適用於單機低併發,不適合分佈式、高併發集羣;級聯更新是強阻塞,存在數據庫更新風暴的風險;外鍵影響數據庫的插入速度。



二、級聯查詢

2.1 示例

在這裏插入圖片描述

2.2 JOIN

連接 說明
INNER JOIN(內連接) 只匹配兩個表的交集
LEFT OUTER JOIN(左外連接) 儘可能的匹配左表
RIGHT OUTER JOIN(右外連接) 儘可能的匹配右表
FULL OUTER JOIN(全連接) 全部匹配

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

由於MySQL不支持FULL JOIN,可以用UNION來實現全連接的功能
在這裏插入圖片描述




三、代碼生成器(MyBatis Generator)

在IDEA上有着豐富的代碼自動生成插件,基本上可以生成絕大部分的domaindaoservicecontroller層的代碼。比如Free MyBatis Plugin自帶的generator、Mybatis Generator(IDEA插件名)、Easy Code、Code Maker等等。

3.1 依賴

		<!-- https://mvnrepository.com/artifact/org.mybatis.generator/mybatis-generator-core -->
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.3.7</version>
        </dependency>

3.2 數據庫連接配置db.properties

MySQL如果沒配置時區,可能需要在url後追加時區serverTimezone=UTC。配置方法在MySQL——MySQL8時區問題這篇博客裏

db.driver-location=E:/repository/mysql/mysql-connector-java/8.0.16/mysql-connector-java-8.0.16.jar
db.driver-class-name=com.mysql.cj.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/demo-test
db.username=root
db.password=root

3.3 生成器配置generatorConfig.xml

通常需要配置的地方有6處:

  1. 添加context節點以配置多數據源。
  2. 添加plugin節點以配置插件。
  3. 修改targetPackage屬性以修改生成文件的路徑。
  4. 修改javaClientGenerator節點的type屬性以ANNOTATEDMAPPER(註解)、XMLMAPPER(xml文件)、MIXEDMAPPER(混合)實現SQL語句。
  5. 添加/修改table節點的tableNamedomainObjectName以配置表到實體的映射。
  6. 添加/修改table/ignoreColumn節點以配置需要忽略的從表到實體的映射。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <properties resource="db.properties"/>

    <classPathEntry location="${db.driver-location}"/>

    <context id="default" targetRuntime="MyBatis3">
        <commentGenerator>
            <property name="suppressDate" value="true"/>
            <property name="suppressAllComments" value="true"/>
        </commentGenerator>

        <jdbcConnection driverClass="${db.driver-class-name}"
                        connectionURL="${db.url}"
                        userId="${db.username}"
                        password="${db.password}">
        </jdbcConnection>

        <javaTypeResolver>
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>

        <javaModelGenerator targetPackage="model.generator" targetProject="./src/main/java">
            <property name="enableSubPackages" value="false"/>
            <property name="constructorBased" value="true"/>
            <property name="trimStrings" value="true"/>
            <property name="immutable" value="false"/>
        </javaModelGenerator>

        <sqlMapGenerator targetPackage="mapper.generator" targetProject="./src/main/resources">
            <property name="enableSubPackages" value="false"/>
        </sqlMapGenerator>

        <javaClientGenerator type="XMLMAPPER" targetPackage="dao.generator" targetProject="./src/main/java">
            <property name="enableSubPackages" value="false"/>
        </javaClientGenerator>

        <table tableName="t_type" domainObjectName="Type"
               enableCountByExample="false"
               enableUpdateByExample="false"
               enableDeleteByExample="false"
               enableSelectByExample="false"
               selectByExampleQueryId="false">
        </table>

        <table tableName="t_hero" domainObjectName="Hero"
               enableCountByExample="false"
               enableDeleteByExample="false"
               enableSelectByExample="false"
               enableUpdateByExample="false">
             <ignoreColumn column="_type_name"/>
        </table>

        <table tableName="t_player" domainObjectName="Player"
               enableCountByExample="false"
               enableDeleteByExample="false"
               enableSelectByExample="false"
               enableUpdateByExample="false">
        </table>
    </context>
</generatorConfiguration>

3.4 配置以Maven插件的方式運行

build/plugins/節點下添加以下插件:

			<plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.7</version>
            </plugin>

默認會從classpath路徑下讀取generatorConfig.xml爲配置文件,通常不需要配置。

classpath是指項目編譯後的根目錄,在Maven的項目目錄中默認爲./src/main/java/./src/main/resources/這兩個目錄

配置完成後的默認命令爲mybatis-generator:generate,並且重複執行並不會覆蓋舊文件。MyBatis Generator通常需要數據庫連接驅動的全限定名。

	<classPathEntry location="${db.driver-location}"/>

不過也可以使用Maven的依賴:

			<plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.7</version>
                <dependencies>
                    <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>8.0.16</version>
                    </dependency>
                </dependencies>
			</plugin>



四、CRUD

4.1 實體關係

在這裏插入圖片描述

4.2 xml文件

查詢通常需要自定義結果映射resultMap,其中id表示主鍵字段映射關係,result表示普通字段的映射關係,一般只需配置property屬性(實體中的字段)和column屬性(表中的字段)。級聯查詢時

  1. collection用於配置與表示關係的實體的映射,以ofType屬性指定集合中的元素類型`。
  2. association用於配置與表示關係的實體的映射,以javaType屬性指定字段類型。

4.2.1 TypeMapper.xml

在這裏插入圖片描述

4.2.2 HeroMapper.xml

在這裏插入圖片描述

4.2.3 PlayerMapper.xml

在這裏插入圖片描述

4.3 配置文件mybatis-config.xml

通常配置文件都是直接放在classpath路徑下的方便讀取。另外如果不把MyBatis交給Spring管理的話,貌似mappers/mapper節點不支持通配符。

<?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="db.properties"/>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${db.driver-class-name}"/>
                <property name="url" value="${db.url}"/>
                <property name="username" value="${db.username}"/>
                <property name="password" value="${db.password}"/>
            </dataSource>
        </environment>
    </environments>
    
    <mappers>
        <mapper resource="mapper/generator/TypeMapper.xml"/>
        <mapper resource="mapper/generator/HeroMapper.xml"/>
        <mapper resource="mapper/generator/PlayerMapper.xml"/>
    </mappers>
</configuration>

4.4 測試類App.java

public class App {
    public static void main(String[] args) {
        SqlSession sqlSession = getSqlSession();
/*
        HeroMapper heroMapper = sqlSession.getMapper(HeroMapper.class);
        Hero h = heroMapper.selectByCascade("花木蘭");
        System.out.println(h);


        PlayerMapper playerMapper = sqlSession.getMapper(PlayerMapper.class);
        Player p = playerMapper.selectByCascade("教主");
        System.out.println(p);
*/

        TypeMapper typeMapper = sqlSession.getMapper(TypeMapper.class);
        Type t = typeMapper.selectByCascade("刺客");
        System.out.println(t);

        sqlSession.close();
    }

    public static SqlSession getSqlSession() {
        String resource = "mybatis-config.xml";

        try (InputStream inputStream = Resources.getResourceAsStream(resource)) {
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            return sqlSessionFactory.openSession();
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(0);
        }
        return null;
    }
}

4.4 IDEA添加toString()的JSON模板

ALT+INSERT打開toString()的模板設置,添加以下模板並應用

public java.lang.String toString() {
final java.lang.StringBuilder sb = new java.lang.StringBuilder("{");
#set ($i = 0)
#foreach ($member in $members)#if ($i == 0)
sb.append("#####
#else
sb.append(",####
#end#if ($member.string || $member.date)
\"$member.name\":\"")
#else
\"$member.name\":")
#end#if ($member.primitiveArray || $member.objectArray)
.append(java.util.Arrays.toString($member.name));
#elseif ($member.string || $member.date)
.append($member.accessor).append('\"');
#else
.append($member.accessor);
#end#set ($i = $i + 1)
#end
sb.append('}');
return sb.toString();
}

4.5 測試輸出

複製輸出到JSON中格式化
在這裏插入圖片描述



四、參考資料

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