一、resultMap標(biāo)簽的使用
1.解決列名和屬性名的不一致:
如果查詢時(shí)使用 resultType 屬性, 表示采用 MyBatis 的Auto-Mapping(自動(dòng)映射)機(jī)制, 即相同的列名和屬性名會(huì)自動(dòng)匹配. 因此, 當(dāng)數(shù)據(jù)庫表的列名和類的屬性名不一致時(shí), 會(huì)導(dǎo)致查不到數(shù)據(jù). 解決該問題可以有兩種方式:
-
起列別名:
查詢時(shí), 可以通過列別名的方式將列名和屬性名保持一致, 繼續(xù)使用自動(dòng)映射, 從而解決該問題. 但是較為麻煩梁呈。
<select id="selAll" resultType="user">
select id id1, username username1, password password2 from t_user
</select>
-
使用<resultMap>標(biāo)簽
<resultMap>用于自定義映射關(guān)系, 可以由程序員自主制定列名和屬性名的映射關(guān)系东羹。一旦使用 resultMap, 表示不再采用自動(dòng)映射機(jī)制鲁僚。
(1)代碼示例:
<mapper namespace="com.zlw.mapper.UserMapper">
<resultMap type="user" id="umap">
<id column="userId" property="userId1"/>
<result column="userName" property="userName1"/>
<result column="userPass" property="userpass1"/>
</resultMap>
<select id="selAll" resultMap="umap">
select* from t_user
</select>
</mapper>
(2)測(cè)試:
@Test
public void Sel() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = factory.openSession();
List<User> list = session.selectList("com.zlw.mapper.UserMapper.selAll");
for (User user : list) {
System.out.println(user);
}
session.close();
}
(3)結(jié)果:
2.多表連接查詢(多對(duì)一):
?????mapper 層只做單表查詢操作, 在 service 層進(jìn)行手動(dòng)裝配, 實(shí)現(xiàn)關(guān)聯(lián)查詢的結(jié)果。
創(chuàng)建兩個(gè)表;
創(chuàng)建兩個(gè)實(shí)體類倦零;
Mapper層:
提供StudentMapper和ClazzMapper, StudentMapper查詢所有學(xué)生信息藐石,ClazzMapper 根據(jù)編號(hào)查詢班級(jí)信息即供。
(1)sql語句:
create table t_class(
id int(3) PRIMARY key auto_increment,
name VARCHAR(20) not null,
room VARCHAR(20)
)
create table t_student(
id int(5) PRIMARY KEY auto_increment,
name VARCHAR(30) not null,
age int(3),
gender CHAR(3),
cid int(3) references t_class (id)
)
(2)映射文件配置:
<select id="selAll" resultType="Student">
select *from t_student
</select>
<mapper namespace="com.zlw.mapper.ClazzMapper">
<select id="findById" resultType="clazz" parameterType="int">
select *from t_class where id = #{0}
</select>
</mapper>
(3)Service層:
public List<Student> selAll() {
//學(xué)生mapper
SqlSession session = MyBatisUtil.getSqlSession();
StudentMapper stumapper= session.getMapper(StudentMapper.class);
//班級(jí)mapper
ClazzMapper clamapper = session.getMapper(ClazzMapper.class);
List<Student> list = stumapper.selAll();
for (Student student : list) {
int id = student.getCid();
Clazz clazz = clamapper.findById(id);
student.setClazz(clazz);
}
session.close();
return list;
}
(4)測(cè)試:
@Test
public void StudentTest() {
StudentService ss = new StudentServiceImpl();
List<Student> list = ss.selAll();
for (Student student : list) {
System.out.println(student);
}
}
3.resultMap的N+1方式實(shí)現(xiàn)多表查詢(多對(duì) 一)
<association>標(biāo)簽的使用;用于關(guān)聯(lián)一個(gè)對(duì)象 于微。
屬性:
property: 指定要關(guān)聯(lián)的屬性名 逗嫡;
select: 設(shè)定要繼續(xù)引用的查詢, namespace+id ;
column: 查詢時(shí)需要傳遞的列 株依;
(1)mapper層:
提供StudentMapper和ClazzMapper, StudentMapper查詢所有學(xué)生信息驱证,ClazzMapper 根據(jù)編號(hào)查詢班級(jí)信息。再StudentMapper 中使用<association>設(shè)置裝配恋腕。
<mapper namespace="com.bjsxt.mapper.StudentMapper">
<resultMap type="student" id="smap">
<!-- N+1查詢時(shí), 同名映射可以省略, 但是只能使用一次 -->
<result property="cid" column="cid" />
<!-- 用于關(guān)聯(lián)一個(gè)對(duì)象 -->
<association property="clazz" select="com.zlw.mapper.ClazzMapper.selById"
column="cid">
</association>
</resultMap>
<select id="selAll" resultMap="smap">
select * from t_student
</select>
</mapper>
<mapper namespace="com.zlw.mapper.ClazzMapper">
<select id="selById" resultType="clazz" parameterType="int">
select * from t_class where id=#{0}
</select>
</mapper>
(2)service層:
@Override
public List<Student> selAll() {
SqlSession session = MyBatisUtil.getSession();
// 學(xué)生mapper
StudentMapper stuMapper = session.getMapper(StudentMapper.class);
List<Student> list = stuMapper.selAll();
session.close(); return list;
}
(3)測(cè)試:
@Test
public void StudentTest() {
StudentService ss = new StudentServiceImpl();
List<Student> list = ss.selAll();
for (Student student : list) {
System.out.println(student);
}
}
4.解決N+1問題:
使用多表表連接查詢語句抹锄;
在 StudentMapper.xml 中定義多表連接查詢 SQL 語句, 一次性查到需要的所有數(shù)據(jù), 包括對(duì)應(yīng)班級(jí)的信息。
通過<resultMap>定義映射關(guān)系, 并通過<association>指定對(duì)象屬性的映射關(guān)系. 可以把<association>看成一個(gè)<resultMap>使用. javaType 屬性表示當(dāng)前對(duì)象, 可以寫全限定路徑或別名荠藤。
(1)MyBatis核心配置文件:
<?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" />
<settings>
<setting name="logImpl" value="LOG4J" />
</settings>
<typeAliases>
<package name="com.zlw.pojo"/>
</typeAliases>
<environments default="dev1">
<environment id="dev1">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="pooled">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<mappers>
<package name="com.zlw.mapper"/>
</mappers>
</configuration>
(2)封裝簡(jiǎn)單的工具類:
package com.zlw.util;
import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MyBatisUtil {
private static SqlSessionFactory factory = null;
static {
try {
InputStream is = Resources.getResourceAsStream("mybatis.xml");
factory = new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession() {
SqlSession session = null;
if (factory != null) {
session = factory.openSession();
}
return session;
}
}
(3)mapper層:
<resultMap type="student" id="umap">
<id property="id" column="id" />
<result property="name" column="name" />
<result property="age" column="age" />
<result property="gender" column="gender" />
<result property="cid" column="cid" />
<association property="clazz" javaType="clazz">
<id property="id" column="cid" />
<result property="name" column="cname" />
<result property="room" column="room" />
</association>
</resultMap>
<select id="selAll2" resultMap="umap">
select s.*,c.name cname ,c.room from t_student s
LEFT JOIN t_class c on s.cid= c.id
</select>
<mapper namespace="com.zlw.mapper.ClazzMapper">
<select id="findById" resultType="clazz" parameterType="int">
select *from t_class where id = #{0}
</select>
</mapper>
(4)service層:
public List<Student> selAll2() {
//學(xué)生mapper
SqlSession session = MyBatisUtil.getSqlSession();
StudentMapper stumapper= session.getMapper(StudentMapper.class);
List<Student> list = stumapper.selAll2();
session.close();
return list;
}
(5)測(cè)試:
@Test
public void StudentTest2() {
StudentService ss = new StudentServiceImpl();
List<Student> list = ss.selAll2();
for (Student student : list) {
System.out.println(student);
}
}
5.resultMap的關(guān)聯(lián)方式實(shí)現(xiàn)多表查詢(一對(duì)多) :
在 ClazzMapper.xml 中定義多表連接查詢 SQL 語句, 一次性查到需要的所有數(shù)據(jù), 包括對(duì)應(yīng)學(xué)生的信息伙单。
通過<resultMap>定義映射關(guān)系, 并通過<collection>指定集合屬性泛型的映射關(guān)系. 可以把<collection>看成一個(gè)<resultMap>使用。ofType 屬性表示集合的泛型, 可以寫全限定路徑或別名哈肖。
- mapper層:
<resultMap type="clazz" id="cmap2">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="room" column="room"/>
<collection property="stus" javaType="list" ofType="student">
<id property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="age" column="age"/>
<result property="gender" column="gender"/>
<result property="cid" column="cid"/>
</collection>
</resultMap>
<select id="selAll2" resultMap="cmap2">
select c.*,s.id sid,s.name sname ,s.age,s.gender,s.cid from t_student s
right JOIN t_class c on s.cid= c.id
</select>
<mapper namespace="com.zlw.mapper.StudentMapper">
<select id="findById" resultType="student">
select *from t_student where cid = #{0}
</select>
</mapper>
- service層:
public List<Clazz> selAll2() {
SqlSession session = MyBatisUtil.getSqlSession();
ClazzMapper mapper = session.getMapper(ClazzMapper.class);
List<Clazz> list = mapper.selAll2();
return list;
}
(3)測(cè)試:
@Test
public void ClazzTest2() {
ClassService cs = new ClazzServiceImpl();
List<Clazz> list = cs.selAll2();
for (Clazz clazz : list) {
System.out.println(clazz);
}
}
6.通過Auto-Mapping實(shí)現(xiàn)多表查詢 :
) 通過 MyBatis 的 Auto-Mapping 機(jī)制及數(shù)據(jù)庫查詢時(shí)的別
名結(jié)合, 可以方便的實(shí)現(xiàn)多表查詢吻育。
SQL 語句中, 別名出現(xiàn)特殊符號(hào)時(shí), 必須進(jìn)行處理. MySQL可以使用(``)符號(hào), Oracle 可以使用("")符號(hào)。
(1)mapper:
<!-- auto -->
<select id="selAll3" resultType="student">
select s.*,c.id `clazz.id`,c.name `clazz.name` ,c.room `clazz.room`
from t_student s
LEFT JOIN t_class c
on s.cid= c.id
</select>
(2)service:
public List<Student> selAll3() {
SqlSession session = MyBatisUtil.getSqlSession();
StudentMapper mapper = session.getMapper(StudentMapper.class);
List<Student> list = mapper.selAll3();
session.close();
return list;
}
(3)測(cè)試:
@Test
public void StudentTest3() {
StudentService ss = new StudentServiceImpl();
List<Student> list = ss.selAll3();
for (Student student : list) {
System.out.println(student);
}
}
二淤井、MyBatis的注解開發(fā)
1.注解開發(fā):
注解是用于描述代碼的代碼. 例如: @Test(用于描述方法進(jìn)行 junit 測(cè)試),@Override(用于描述方法的重寫), @Param(用于描述屬性的名稱)布疼。
使用前必須先導(dǎo)包 摊趾;
使用注解一般用于簡(jiǎn)化配置文件. 但是, 注解有時(shí)候也不是很友好(有時(shí)候反而更麻煩), 例如動(dòng)態(tài) SQL。
注解和配置文件可以配合使用游两。
-
注解的屬性:
屬性的設(shè)定方式是: 屬性名=屬性值 ;
基本類型和 String, 可以直接使用雙引號(hào)的形式
數(shù)組類型, name={值 1, 值 2, ...}; 如果數(shù)組元素只有一個(gè), 可以省略大括號(hào)严就;
對(duì)象類型, name=@對(duì)象名(屬性) 。
如果屬性是該注解的默認(rèn)屬性, 而且該注解只配置這一個(gè)屬性, 可以將屬性名省略器罐。
2.使用注解完成單表增刪改查:
@Select: 類似于<select>
@Insert: 類似于<insert>
@Update: 類似于<update>
@Delete: 類似于<delete>
(1)mapper:
package com.zlw.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import com.zlw.pojo.Student;
public interface StudentMapper {
@Select("select * from t_student")
List<Student> sleAll();
@Insert("insert into t_student values(default,#{name},#{age},#{gender},#{cid})")
int add(Student stu);
@Update("update t_student set age=#{1} where id=#{0}")
int update(int id, int age);
@Delete("delete from t_student where id = #{0}")
int delete(int id);
}
(2)測(cè)試:
package com.zlw.test;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import com.zlw.mapper.StudentMapper;
import com.zlw.pojo.Student;
import com.zlw.util.MyBatisUtil;
public class Test01 {
@Test
public void selAll() {
SqlSession session = MyBatisUtil.getSqlSession();
StudentMapper mapper = session.getMapper(StudentMapper.class);
List<Student> list = mapper.sleAll();
for (Student student : list) {
System.out.println(student);
}
session.close();
}
@Test
public void add() {
SqlSession session = MyBatisUtil.getSqlSession();
StudentMapper mapper = session.getMapper(StudentMapper.class);
Student stu = new Student();
stu.setName("Dave");
stu.setAge(18);
stu.setGender("男");
stu.setCid(2);
int num = mapper.add(stu);
if(num>0) {
System.out.println("添加成功梢为!");
session.commit();
}else {
System.out.println("添加失敗轰坊!");
session.rollback();
}
session.close();
}
@Test
public void update() {
SqlSession session = MyBatisUtil.getSqlSession();
StudentMapper mapper = session.getMapper(StudentMapper.class);
int num = mapper.update(6,20);
if(num>0) {
System.out.println("修改成功铸董!");
session.commit();
}else {
System.out.println("修改失敗肴沫!");
session.rollback();
}
session.close();
}
@Test
public void delete() {
SqlSession session = MyBatisUtil.getSqlSession();
StudentMapper mapper = session.getMapper(StudentMapper.class);
int num = mapper.delete(6);
if(num>0) {
System.out.println("刪除成功粟害!");
session.commit();
}else {
System.out.println("刪除失敗颤芬!");
session.rollback();
}
session.close();
}
}
3.其他注釋:
@Results: 類似于<resultMap>
@Result: 類似于<resultMap>的子標(biāo)簽
@One: 類似于<association>
@Many: 類似于<collection>
- 實(shí)現(xiàn)多表查詢操作:
(1)mapper:
public interface StudentMapper {
@Select("select *from t_student")
@Results(value= {
@Result(column="id",property = "id", id=true),
@Result(column = "name",property = "name"),
@Result(column = "age",property = "age"),
@Result(column = "gender",property = "gender"),
@Result(column = "cid",property = "cid"),
@Result(column = "cid",property = "clazz",one =@One(select= "com.zlw.mapper.ClazzMapper.selAll"))
})
List<Student> selAll();
}
public interface ClazzMapper {
@Select("select *from t_class where id = #{0}")
Clazz selAll(int id);
}
(2)測(cè)試:
@Test
public void selAll() {
SqlSession session = MyBatisUtil.getSqlSession();
StudentMapper mapper= session.getMapper(StudentMapper.class);
List<Student> list = mapper.selAll();
for (Student student : list) {
System.out.println(student);
}
}
三悲幅、MyBatis的運(yùn)行原理
1.MyBatis中涉及的接口和類:
- 類:
(1)Resources:用于加載MyBatis核心配置文件;
(2)XMLConfigBuilder:用于解析xml文件站蝠;
(3)Configuration:用于存放xml文件解析后的結(jié)果汰具;
(4)DefaultSqlSessionFactory:是 SqlSessionFactory接口的實(shí)現(xiàn)類,創(chuàng)建時(shí)需要使用Configuration 對(duì)象菱魔;
(5)DefaultSqlSession:是 SqlSession 接口的實(shí)現(xiàn)類留荔;
- 接口:
(1)SqlSession:是MyBatis操作的核心;
(2)TransactionFactory:用于生產(chǎn)Transaction對(duì)象澜倦;
(3)Transaction:用于表示操作數(shù)據(jù)庫的事務(wù)對(duì)象聚蝶;
(4)Executor:是MyBatis的核心執(zhí)行器,類似于jdbc中的Statement藻治,常用的實(shí)現(xiàn)類是SimpleExecutor碘勉。
2.MyBatis的運(yùn)行原理:
??????當(dāng)MyBatis運(yùn)行開始時(shí),先通過Resource加載核心配置文件桩卵,再使用XMLConfigBuilder對(duì)配置文件進(jìn)行解析验靡,將解析結(jié)果封裝為Configuration對(duì)象, 然后, 使用Configuration對(duì)象構(gòu)建一個(gè)DefaultSqlSessionFactory對(duì)象, 至此, SqlSession工廠構(gòu)建完成。
??????接下來, 通過工廠對(duì)象調(diào)用 openSession 方法創(chuàng)建SqlSession 對(duì) 象 吸占;在 這 個(gè) 過 程 中 , 需 要 通 過TransactionFactory生成 Transaction 對(duì)象, 并且, 還需要?jiǎng)?chuàng)建核心執(zhí)行器 Executor 對(duì)象, 之后, 通過這些對(duì)象來創(chuàng)建DefaultSqlSession對(duì)象, 至此, SqlSession對(duì)象創(chuàng)建成功晴叨。
??????之后, 通過 SqlSession 對(duì)象執(zhí)行相應(yīng)的操作, 如果執(zhí)行成功, 調(diào)用 commit 方法提交事務(wù); 如果失敗, 調(diào)用rollback 方法事務(wù)回滾。最后, 調(diào)用 close 方法關(guān)閉session 資源矾屯。以上, 就是 MyBatis 的運(yùn)行原理兼蕊。