MyBatis는 고급 협회 쿼리 기능을 제공하며 데이터베이스에서 얻은 결과 세트를 정의 된 Java Bean에 쉽게 매핑 할 수 있습니다. 다음은 Mybatis가 일반적인 일대일 및 다중 관계 복잡한 매핑을 어떻게 다루는지를 보여주는 예입니다.
사용자가 여러 블로그를 열고, 블로그에 기사를 게시하고, 댓글을 허용하며, 기사를 태그 할 수있는 간단한 블로그 시스템을 설계하십시오. 블로그 시스템은 주로 다음 테이블로 구성됩니다.
저자 테이블 : 저자 정보 테이블, 저자의 정보, 사용자 이름 및 비밀번호, 이메일 주소 등을 기록하십시오.
블로그 테이블 : 블로그 테이블, 저자는 여러 블로그를 열 수 있습니다. 즉, 저자와 블로그의 관계는 일대일입니다.
게시물 표 : 기사 기록 테이블, 게시물 게시 시간, 제목, 텍스트 및 기타 정보 기록; 블로그에는 많은 기사가있을 수 있으며 블로그와 게시물의 관계는 일대일입니다.
주석 테이블 : 기사 주석 표, 기록 기사 주석, 기사에는 많은 의견이있을 수 있습니다. 게시물과 의견 사이의 서신은 일대일입니다.
태그 테이블 : 기사의 태그 분류를 나타내는 태그 테이블. 기사는 여러 개의 태그를 가질 수 있고 다른 기사에 태그를 적용 할 수 있으므로 태그와 게시물의 관계는 다수의 관계입니다. (태그와 포스트 사이의 다수의 관계는 post_tag 테이블을 통해 반영됩니다)
Post_tag 테이블 : 기사와 태그 사이의 서신을 기록합니다.
일반적으로 말하면, 각 테이블의 구조를 기반으로 해당 Javabean (또는 Pojo)을 만들어 테이블의 기본 CRUD 작업을 완료합니다.
단일 테이블의 위의 Javabean 정의는 때때로 비즈니스 요구를 충족시킬 수 없습니다. 비즈니스에서 블로그 객체는 아래 그림과 같이 저자 및 기사 목록에 대한 정보가 있어야합니다.
그러한 수업의 인스턴스를 얻으려면 적어도 몇 단계가 필요합니다.
1. 블로그 테이블의 블로그 ID를 통해 블로그 정보를 쿼리하고 블로그와 제목을 블로그 개체에 할당하십시오.
2. 블로그 정보의 쿼리 authorID에 따르면 저자 테이블로 이동하여 해당 저자 정보를 얻고 저자 객체를 얻은 다음 블로그 객체에 할당하십시오.
3. BlogID에 따르면, 게시물 테이블의 해당 게시물 기사 목록을 쿼리하고 목록을 블로그 개체에 할당하십시오.
이러한 방식으로 최소 3 개의 쿼리 문이 하단 계층에서 호출됩니다. 다음 코드를 참조하십시오.
/** blogid*/ public static bloginfo angicqueryontest (String blogid) {bigdecimal id = new bigdecimal (blogid); sqlsession session = sqlsessionfactory.opensession (); BlogInfo BlogInfo = 새로운 blogInfo (); // 1. BlogID에 따라 블로그 객체를 쿼리하고 BlogInfo Blog = (Blog) Session.Selectone ( "com.foo.bean.blogmapper.selectByPrimaryKey", id)에 값을 설정합니다. bloginfo.setBlogid (blog.getBlogid ()); bloginfo.settitle (blog.getTitle ()); // 2. 블로그의 저자에 따르면, 데이터베이스를 입력하여 저자 정보를 쿼리하고 결과를 BlogInfo 객체 author = (author) session.selectone ( "com.foo.bean.authormapper.selectbyprimarykey", blog.getauthorid ())로 설정하십시오. BlogInfo.SetAuthor (저자); // 3. 게시물 객체를 쿼리하고 BlogInfo 목록으로 설정하십시오. posts = session.selectList ( "com.foo.bean.postmapper.selectbyBlogid", blog.getBlogid ()); BlogInfo.setPosts (게시물); // json 문자열 형식으로 객체를 인쇄 jsonobject 객체 = new JsonObject (bloginfo); System.out.println (Object.toString ()); react bloginfo; }위의 코드에서 BlogInfo 객체를 얻는 것이 더 번거 롭다는 것을 알 수 있습니다. 데이터베이스 쿼리를 총 세 번 호출하고 필요한 정보를 얻은 다음 BlogInfo 객체를 조립해야합니다.
중첩 명세서 쿼리
Mybatis는 위의 작업을 크게 단순화하고 다음과 같이 구성 및 코드를 추가 할 수있는 중첩 명령문 쿼리라는 메커니즘을 제공합니다.
<resultmap type = "com.foo.bean.bloginfo"id = "bloginfo"> <id column = "blog_id"property = "blog_id"속성 = "blogid" /> <result column = "title"property = "title" /> <Association Property = "author"열 = "blog_author_id"javatype = "com.foo.bean.author" select = "com.foo.bean.authormapper.selectbyprimarykey"> </assion> <collection property = "collect"column = "blog_id"oftype = "com.foo.bean.post"select = "com.foo.bean.postmapper.selectbyBlogid"</resultmap> <select id = "querybloginfobyid" resultmap = "bloginfo"parametertype = "java.math.bigdecimal"> b.blog_id, b.title, b.author_id는 louluan.blog b에서 blog_author_id로 b.blog_id = #{blogid, jdbctype = decimal} </select>를 선택합니다. /** blogid*/ public static bloginfo nestedQueryOntest (String BlogId) {bigdecimal id = new bigdecimal (blogid); sqlsession session = sqlsessionfactory.opensession (); BlogInfo BlogInfo = 새로운 blogInfo (); blogInfo = (blogInfo) session.selectone ( "com.foo.bean.blogmapper.querybloginfobyid", id); jsonObject Object = new JsonObject (bloginfo); System.out.println (Object.toString ()); react bloginfo; }이전 쿼리는 위의 코드를 통해 완전히 실현 될 수 있습니다. 여기에는 bloginfo = (bloginfo) session.selectone 만 필요합니다 ( "com.foo.bean.blogmapper.querybloginfobyid", id); 코드에서는 복잡한 BlogInfo 객체를 얻을 수 있습니다.
중첩 된 명세서 쿼리의 원리
위 코드에서 Mybatis는 다음 과정을 수행합니다.
1. 먼저 블로그 테이블에서 resultset 결과를 얻으려면 해당 쿼리 블로그 인포비이드의 해당 문을 실행합니다.
2. 결과 세트의 다음 유효한 레코드를 꺼낸 다음 resultMap에 의해 정의 된 매핑 사양을 기반으로 해당 BlogInfo 객체를 작성하십시오.
3. BlogInfo에 저자 속성을 할당하려면 관련 쿼리가 있음을 알 수 있습니다. 현재 Mybatis는 먼저 선택 쿼리 문을 실행하여 반환 된 결과를 얻고 결과를 BlogInfo의 저자 속성으로 설정합니다.
4. BlogInfo의 게시물을 할당 할 때 유사한 프로세스도 있습니다.
5. 결과 세트까지 2 단계를 반복하십시오. 다음 () == 거짓;
다음은 BlogInfo 객체 구성 할당 프로세스의 개략도입니다.
이러한 종류의 관련 중첩 쿼리의 매우 좋은 기능은 SELECT 문을 재사용하고 간단한 선택 문의 조합을 통해 복잡한 객체를 구성 할 수 있다는 것입니다. com.foo.bean.authormapper.selectbyprimarykey 및 com.foo.bean.postmapper.selectbyblogid 위에 중첩 된 두 개의 선택 문은 독립적으로 사용할 수 있습니다.
n+1 문제
소위 N+1 문제. 관련된 중첩 쿼리는 결과 세트를 표시 한 다음이 결과 세트의 각 레코드에 따라 관련 쿼리가 수행됩니다.
이제 하나의 중첩 쿼리 만 있다고 가정하고 (즉, resultmap 안에 연결 태그가 있다고 가정하고, 쿼리에 의해 반환 된 항목의 수는 n이고, 관련 쿼리 문은 n 번 실행되며, 쿼리 자체는 결과를 쿼리로 한 번 반환하고 총 n+1 번은 데이터베이스에 액세스해야합니다. N이 비교적 크면 데이터베이스 액세스 소비는 매우 큽니다! 따라서 이러한 종류의 중첩 명령문 쿼리를 사용하는 사용자는 N 값이 크지 않도록 신중하게 고려해야합니다.
예를 들어, select 문 자체는 com.foo.bean.blogmapper.querybloginfobyid가 1으로 1* (1+1) = 3 배에 액세스해야합니다.
중첩 결과 쿼리
중첩 된 명령문을 쿼리하면 불확실한 데이터베이스 액세스 시간이 발생하여 성능에 영향을 줄 수 있습니다. Mybatis는 또한 일종의 중첩 결과 쿼리를 지원합니다. 즉, 일대일, 다수 및 다수의 상황에 대한 쿼리를 위해 Mybatis는 공동 쿼리를 통해 데이터베이스에서 결과를 검색 한 다음 일대일, 다수의 관계 및 구성에서 결과를 기반으로 결과를 변환합니다.
BlogInfo의 결과 맵을 재정의하십시오
<resultmap type = "com.foo.bean.bloginfo"id = "bloginfo"> <id councle = "blog_id"property = "blog_id"속성 = "blogid"/<result column = "title"property = "thit 열 = "user_name"property = "username"/> <result column = "product"속성 = "암호"/> <결과 열 = "이메일"속성 = "email"속성 = "이메일"/> <결과 열 = "biography"property = "viography"/> </association property = "collection"column = "blog_post_id"oftype = "com.foo.bean.post"> <id column = "post_" "idid =" "post _"idid " <결과 열 = "blog_id"속성 = "blogid"/> <result column = "create_time"property = "createTime"/> <result column = "subject"property = "subject"property = "subject"/<result column = "body"property = "body"/<result column = "draft"propert = "draft"/> </collection> </resultmap>
해당 SQL 문은 다음과 같습니다.
< "QueryAllBlogInfo"QueryAllBlogInfo = "blogInfo"> blog_author_id, a.author_id, a.user_name, a.password, a.email, a.biagraph, p.post_id, p.blog_id, p.create, p.crate, p.crate, p.crate_did, p.crate_did, p.blog_id. b 왼쪽 외부 조인 author a on b.author_id = a.author_id 왼쪽 외부 조인
/** 모든 블로그에 대한 모든 정보를 받으십시오*/ public static bloginfo nestedResultOntest () {sqlsession session = sqlsessionfactory.opensession (); BlogInfo BlogInfo = 새로운 blogInfo (); blogInfo = (blogInfo) session.selectone ( "com.foo.bean.blogmapper.queryallbloginfo"); jsonObject Object = new JsonObject (bloginfo); System.out.println (Object.toString ()); react bloginfo; } 중첩 된 결과 쿼리의 실행 단계 :
1. 결과 세트를 얻기 위해 테이블의 해당 관계에 따라 조인 작업을 수행합니다.
2. 결과 세트 정보 및 resultmap 정의 정보에 따르면 BlogInfo의 정보 정의 정보에 따라 BlogInfo를 구성하기 위해 리턴 된 결과 세트를 조립하고 할당합니다.
3. 구성된 결과 목록 <Bloginfo> 결과를 반환하십시오.
관련 결과 쿼리의 경우, 다중 하나의 관계 인 경우 <Association Property = "Author"열 = "blog_author_id"javatype = "com.foo.bean.author"로 구성됩니다. Mybatis는 열 속성에 해당하는 author_id 값을 통해 메모리에서 데이터를 가져와 작성자 객체로 캡슐화합니다.
블로그와 게시물 사이의 관계와 마찬가지로 일대일 관계 인 경우 <Collection Property = "Posts"열 = "blog_post_id"oftype = "com.foo.bean.post">로 구성됩니다.
관련 결과를 쿼리하려면 데이터베이스를 한 번만 쿼리하면 결과의 통합 및 어셈블리가 모두 메모리에 배치됩니다.
위의 내용은 모든 블로그 정보를 쿼리하여 일대일 및 다중 매핑 객체 처리를 보여주는 것입니다.
추신 : 자기 관련 매핑의 예 :
엔티티 클래스
공개 클래스 모듈 {private int id; 개인 문자열 키; 개인 문자열 이름; 비공개 모듈 상위 모듈; 개인 목록 <모듈> 어린이 모듈; 개인 문자열 URL; 개인 int 정렬; 개인 문자열 쇼; 개인 문자열 델; public int getid () {return id; } public void setid (int id) {this.id = id; } public String getKey () {return 키; } public void setkey (문자열 키) {this.key = 키; } public String getName () {return name; } public void setName (문자열 이름) {this.name = 이름; } public module getParentModule () {return parentModule; } public void setParentModule (module parentModule) {this.parentModule = parentModule; } public String getUrl () {return url; } public void seturl (String URL) {this.url = url; } public int getsort () {return sort; } public void setSort (int sort) {this.sort = sort; } public String getShow () {return show; } public void setshow (문자열 show) {this.show = show; } public String getDel () {return del; } public void setdel (String del) {this.del = del; } 공개 목록 <모듈> getChildrenModules () {return ChildrenModules; } public void setchildrenmodules (list <모듈> childrenmodules) {this.childrenmodules = childrenmodules; }} XML 코드 : <mapper namespace = "com.sagaware.caraccess.mapper.mapper.modulemapper"> <resultmap type = "module"id = "moduleresultMap"> <id property = "id"column = "module_id"/> <result property = "module_key"/> <result property = "namecul ="modle _ rengle ""rengle ""rengle ""renuct propegry = "module" "module_id"/> <result property = "module" "rengle" "rengle" "renuct 속성. 열 = "module_url"/> <result property = "sort"column = "module_sort"/> <result property = "show"column = "module_show"/> <result property = "del"column = "module_del"/<!-쿼리-<acoush at parent module = "parentmodule"column = "module_parent_id"select = "getmod" 서브 모드-> <collection property = "childrenmodules"column = "module_id"select = "getChildrenModules"/> </resultmap> <select id = "getModules"ParameterType = "String"resultmap = "moduleresultMap"> select * from tb_module = 2 </select> module id = "getMododeid" parametertype = "int"resultmap = "moduleresultmap"> select *에서 tb_module에서 module_id = #{module_id} </select> <select> < "getchildrenmodues"parametertype = "int"resultmap = "moduleresultmap"> select * from module_} #{select_id = #{elid} </맵퍼>