【MyBatis学習10】関連関係association:1対1関連の3つの方法


このブログのアドレス:http://blog.csdn.net/soonfly/article/details/63688288(転載は出典を明記してください)
本編は主に関連関係を述べる:一対一の関係と一対多の関係.まず5つのテーブルを作成します:【MyBatis学习10】关联关系association:1对1关联的三种方法_第1张图片
DROP TABLE IF EXISTS `category`;
CREATE TABLE `category` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `catename` varchar(50) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;


DROP TABLE IF EXISTS `order`;
CREATE TABLE `order` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `orderno` varchar(20) NOT NULL COMMENT '     ',
  `totalprice` decimal(10,2) DEFAULT NULL COMMENT '    ',
  `create_time` int(11) NOT NULL COMMENT '    ',
  `create_userid` int(10) unsigned NOT NULL COMMENT '    ',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8


DROP TABLE IF EXISTS `order_detail`;
CREATE TABLE `order_detail` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `order_id` int(10) unsigned NOT NULL,
  `product_id` int(10) unsigned NOT NULL,
  `productname` varchar(50) NOT NULL COMMENT '    :  ',
  `price` decimal(10,2) NOT NULL COMMENT '    :  ',
  `num` int(10) unsigned NOT NULL COMMENT '    ',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8


DROP TABLE IF EXISTS `product`;
CREATE TABLE `product` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `productname` varchar(50) NOT NULL,
  `price` decimal(10,2) DEFAULT NULL,
  `cateid` int(11) NOT NULL DEFAULT '1',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(50) DEFAULT NULL,
  `password` varchar(50) DEFAULT NULL,
  `salt` varchar(50) DEFAULT NULL,
  `sex` smallint(1) DEFAULT NULL COMMENT '0-   1-  2- ',
  `address` varchar(50) DEFAULT NULL,
  `cellphone` varchar(30) DEFAULT NULL,
  `email` varchar(30) DEFAULT NULL,
  `islock` smallint(1) unsigned NOT NULL DEFAULT '0',
  `isvalidate` smallint(1) unsigned NOT NULL DEFAULT '1',
  `isdel` smallint(1) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=111 DEFAULT CHARSET=utf8;

5つの表関係は以下の通りである:【MyBatis学习10】关联关系association:1对1关联的三种方法_第2张图片図の4つの関係線を整理する:1、1人のユーザーは0つ以上の注文を持つことができる:[user表]->[order表]は1対多(0.n)関係2、1つの有効な注文は1つ以上の商品を購入して記録する:[order表]->[order_detail表]は1対多(1.n)関係3、1つの商品記録は必ず1つの製品の詳細に対応する:[order_detail表]->[productテーブル]は1対1関係4、1商品分類で0個以上の商品がある可能性がある:[categoryテーブル]->[productテーブル]は1対多(0.n)関係5、すべての1対多関係であり、逆に必ず1対1関係である.例えば[userテーブル]->[orderテーブル]が1対多(0.n)関係である場合、逆に[orderテーブル]->[userテーブル]が1対1関係である.各注文には対応する一意のユーザーがいます.すべての1対1の関係は、逆に必ずしも1対1の関係ではないことに注意してください.例えば[order_detailテーブル]->[productテーブル]は1対1の関係であり、逆に[productテーブル]->[order_detailテーブル]は1対1の関係ではない.同じ製品が複数の異なる注文リストに登場する可能性があるので(人気商品はみんな買いたいですか)
これは一対一の関係[order表]->[user表]が1対1の関係であるので、これを持って手を練習します.1対1の関連付けは、テーブル外部キーの拡張に使用されます.バックグラウンドシステムで次のフィールドで受注リストを表示します.【MyBatis学习10】关联关系association:1对1关联的三种方法_第3张图片[orderテーブル]にはユーザー名、ユーザーアドレス、連絡先の3つのフィールドがなく、creat_useridは、クエリに対応するユーザ情報を関連付けます.クエリ文は次のとおりです.
SELECT `order`.*,`user`.username,`user`.address,`user`.cellphone 
    FROM `order`,`user` 
    WHERE `order`.create_userid=`user`.id

3つの方法で実現できます.
一、新規POJOオブジェクトを拡張し、associationラベルを使用しない
step1.テーブルに対応するOrderクラスがありますが、ユーザー名、ユーザーアドレス、連絡先の3つのフィールドはありません.クラスOrderExtendを新規作成し、フィールドを拡張します.
public class OrderExtend extends Order{
    public OrderExtend() {
        super();
    }
    /*           ,    ,         */
    String username;
    String address;
    String cellphone;

    /*  get set  */
    getter and setter....
}

step2.インタフェースおよびXmlの作成
public interface OrderExtendMapper {
    //        ,        
    public OrderExtend getByOrderno(String orderno) throws Exception;
    //      ,        
    public List getList() throws Exception;
}
"twm.mybatisdemo.mapper.OrderExtendMapper">
    

    

step3.よびだし
public static void main(String[] args) throws Exception {
        SqlSession session = SqlSessionAssist.getSession();

        OrderExtendMapper ordermapper = session
                .getMapper(OrderExtendMapper.class);
        OrderExtend order = ordermapper.getByOrderno("M201209012578917");
        System.out.println(order.getOrderno() + "," + order.getUsername() + ","
                + order.getAddress() + "," + order.getCellphone());
    }

二、(推奨)sqlでクエリーを結合し、associationラベルを使用する
これは新しい拡張クラスを作成する必要はありません.Orderクラスでは、クエリーされたユーザー関連データをassociationラベルでuserにマッピングするUserタイプのプロパティを追加します.associationは、1対1の関連関係を確立するために使用されます.ここでproperty:オブジェクトのプロパティ名javaTypeを指定:マッピングするオブジェクトのタイプを指定します.
step1.Orderクラスで、Userタイプの属性を追加します.
public class OrderExtend extends Order{
    /*           ,    ,         */
    String username;
    String address;
    String cellphone;
    User user;

    public User getUser() {
        return user;
    }
    public void setUser(User user) {
        this.user = user;
    }
    /*  get set  */
    getter and setter....
}

step2.マッパーインタフェースの作成とXmlの構成twm.mybatisdemo.mapperパッケージの下でOrderMapperを作成する.java:
public interface OrderMapper {
    //        ,        
    public Order getByOrderno(String orderno) throws Exception;
    //      ,        
    public List getList() throws Exception;
}

OrderMapper.xml:
<mapper namespace="twm.mybatisdemo.mapper.OrderMapper">
    
    <resultMap type="Order" id="OrderMap">
        
        <id column="id" property="id" />
        <result column="orderno" property="orderno" />
        <result column="create_time" property="create_time" />
        <result column="create_userid" property="create_userid" />
        
        
        <association property="user" javaType="User">
            <result column="username" property="username" />
            <result column="address" property="address" />
            <result column="cellphone" property="cellphone" />
        association>
    resultMap>

    <select id="getByOrderno" parameterType="String"
        resultMap="OrderMap">
        SELECT
        `order`.*,`user`.username,`user`.address,`user`.cellphone
        FROM `order`
        ,`user`
        WHERE `order`.create_userid=`user`.id AND
        `order`.orderno=#{orderno}
    select>

    <select id="getList" resultMap="OrderMap">
        SELECT
        `order`.*,`user`.username,`user`.address,`user`.cellphone
        FROM `order`
        ,`user`
        WHERE `order`.create_userid=`user`.id
    select>
mapper>

step3.よびだし
public static void main(String[] args) throws Exception {
    SqlSession session = SqlSessionAssist.getSession();

    OrderMapper ordermapper = session.getMapper(OrderMapper.class);
    Order order = ordermapper.getByOrderno("M201209012578917");
    System.out.println(order.getOrderno() + ","
            + order.getUser().getUsername() + ","
            + order.getUser().getAddress() + ","
            + order.getUser().getCellphone());

}

三、sql連合クエリーを使わず、associationの遅延ロードによって実現する
遅延ロードとは?注文情報を先に照会すれば、ビジネス要件を満たすことができる場合、ユーザーは照会されず、ユーザー情報が使用された場合にのみユーザー情報を照会します.ユーザー情報をオンデマンドで照会することは、遅延ロードです.たとえば、OrderのgetUserメソッドを呼び出して関連するuserデータを取得した場合にのみ、データベースクエリuserテーブルがトリガーされます.
mybatisのデフォルトでは遅延ロードはオンになっていません.SqlMapConfigでなければなりません.xmlでsetting構成を設定します.LazyLoadingEnabled:グローバル設定の怠惰ロード.「false」に設定すると、関連するすべてのロードが初期化されます.許容値は、true|falseです.デフォルト:false aggressiveLazyLoading:trueに設定すると、リラウドされたオブジェクトは、任意のリラウド属性ですべてロードされる可能性があります.そうでなければ、各プロパティは必要に応じてロードされます.許容値は、true|falseです.デフォルト:true
第2の方法と比べて、他は変わらない.ただし、DAOImplementレイヤにはいくつかの変更があり、XMLファイルは3つの場所を調整します.
1つ目:ユーザー・クエリー・ステートメントを追加します.

<select id="getUser" parameterType="int" resultType="User">
    SELECT
    `username`,`address`,`cellphone`
    FROM `user`
    WHERE `id` =#{_parameter}
select>

2つ目:元resultMapのassociationラベルを
property="user" javaType="User" column="create_userid" select="getUser" />

3つ目は、getByOrdernoとgetListクエリー文を通常のselect単一テーブルクエリーに変更します.


<mapper namespace="twm.mybatisdemo.mapper.OrderMapper">
    
    <resultMap type="Order" id="OrderMap">
        
        <id column="id" property="id" />
        <result column="orderno" property="orderno" />
        <result column="create_time" property="create_time" />
        <result column="create_userid" property="create_userid" />
        
        
        <association property="user" javaType="User" column="create_userid"
            select="getUser" />
    resultMap>


<select id="getUser" parameterType="int" resultType="User">
    SELECT
    `username`,`address`,`cellphone`
    FROM `user`
    WHERE `id` =#{_parameter}
select>

    <select id="getByOrderno" parameterType="String" resultMap="OrderMap">
        SELECT * FROM `order`  WHERE `order`.orderno=#{orderno}
    select>

    <select id="getList" resultMap="OrderMap">
        SELECT * FROM `order` 
    select>
mapper>

すべてOKです.associationのいくつかのプロパティ:property:内部オブジェクトプロパティ名javaType:内部マッピングされたオブジェクトのタイプを指定します.column:select文に渡すパラメータは、外部キーフィールドを指定することに相当します.select:ユーザークエリー文のIDを指定する
getUserユーザークエリーこの文は、twm.mybatisdemo.mapper.UserMapper(UserMapper.xml)selectByIdクエリーが作成されたため、省略することもできます.ここでgetUserのクエリーを削除して、associationを変更することができます.
property="user" javaType="User" column="create_userid" select="twm.mybatisdemo.mapper.UserMapper.selectById" />

実際、ほとんどのビジネスシーンに表示されるテーブルでは、複数のテーブルフィールドが使用されます.遅延ロードを使用すると、N+1の問題が発生します.N+1問題とは?各Order内部のUserオブジェクトを取得するごとにselectクエリが行われるので、実行中にOrderのgetListメソッドが実行されると、SQLはまず1回クエリを行い、クエリ結果がN件の受注レコードがある場合、実際には各受注にselectユーザのクエリが1回実行され、合計n回実行されることが表示されます.SQLは合計n+1回実行された.2番目の方法では、連合クエリーを1回だけ行うのに比べて、この方法は効果的ではありません.ビジネスシーンのテーブルにフィールドが表示され、テーブルにまたがっていない場合は、遅延ロード方式を採用できます.
このブログのアドレス:http://blog.csdn.net/soonfly/article/details/63688288(転載は出典を明記してください)