我們知道在mybatis框架中,config.xml中會關聯到許多的XxxxMapper的xml文件,這些文件又對應着一個個的接口,來觀察下這些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.briup.mappers.StudentMapper">
首先是如何執行sql語句
<insert id="insertStudent" parameterType="Student"> INSERT INTO STUDENTS(STUD_ID,NAME,EMAIL,PHONE) VALUES(#{studId},#{name},#{email},#{phone}) </insert>
ID屬性為insertStudent,可以在當前xml文件中的名空間 com.briup.mappers.StudentMapper.insertStudent中唯一標識該sql語句。parameterType 屬性是一個完全限定類名或者是一個類型別名alias。
可以如下調用這個sql語句:
int count = sqlSession.insert("com.briup.mappers.StudentMapper.insertStudent", student);
sqlSession.insert() 方法返回執行 INSERT 語句后所影響的行數。
或者使用映射接口Mapper來調用:
public interface Student Mapper{ int insertStudent(Student student); } StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); int count = mapper.insertStudent(student);
INSERT插入,(自動生成主鍵)
在INSERT語句中,可以自動生成主鍵列 STUD_ID 的值。
使用useGeneratedKeys和keyProperty屬性讓數據庫生成auto_increment列的值,並將生成的值設置到其中一個輸入對象屬性內,如下所示:
<insert id="insertStudent2" parameterType="Student" useGeneratedKeys="true" keyProperty="studId"> INSERT INTO STUDENTS(NAME, EMAIL, PHONE) VALUES(#{name},#{email},#{phone}) </insert>
這里STUD_ID列值將會被數據庫自動生成(如
mysql),並且生成的值會被設置到student對象的studId屬性上
注意:
有些數據庫,如
oracle,並不支持AUTO_INCREMENT列,但是oracle中可以使用序列來生成主鍵值。
例如:使用序列my_seq來生成SUTD_ID主鍵值。使用如下代碼來生成主鍵:
drop sequence my_seq;
create sequence my_seq;
<insert id="insertStudent" parameterType="Student"> <selectKey keyProperty="studId" resultType="int" order="BEFORE"> SELECT my_seq.nextval FROM DUAL </selectKey> INSERT INTO STUDENTS(STUD_ID,NAME,EMAIL, PHONE) VALUES(#{studId},#{name},#{email},#{phone}) </insert>
這里使用了<selectKey>標簽來獲取主鍵值,並將值保存到Student對象的studId 屬性上。屬性order="before" 表示,MyBatis將取得序列的下一個值作為主鍵值,並且在執行INSERT語句之前將值設置到studId屬性上。
update and delete
<update id="updateStudent" parameterType="Student"> UPDATE STUDENTS SET NAME=#{name}, EMAIL=#{email}, PHONE=#{phone} WHERE STUD_ID=#{studId} </update> <delete id="deleteStudent" parameterType="int"> DELETE FROM STUDENTS WHERE STUD_ID=#{id} </delete>
注意:在insert updata delete 標簽中都沒有resultType這種屬性,但是並不能說使用這三種SQL語句對應的方法就沒有返回值 ,我們可以在接口中為這三種方法添加int類型的參數,返回的是一個int類型的值,這個值表示SQL語句執行后影響的行數。
SELECT 查詢語句
MyBatis真正強大的功能,在於映射SELECT查詢結果到java的各種類型上。說到查詢,就不能不提映射結果集,有一對一映射,一對多映射,多對多映射。
一個簡單的select查詢配置,如下所示:
<select id="findStudentById" parameterType="int" resultType="Student"> SELECT STUD_ID, NAME, EMAIL, PHONE FROM STUDENTS <!--這里的#{}中的值,如果傳的是myBatis中封裝的類型,比如int,Integer,那么這里的#{}中的值是做形參,命名不限--> <!--如果是pojo類型的參數傳入另當別論--> WHERE STUD_ID=#{studId} </select>
像這樣寫存在一個問題,在Student類型中如果沒有STUD_ID屬性與查詢出來的值對應,我們可以給這個列起個別名,如果自己封裝了resultMap那就另說
SELECT STUD_ID AS STUDID, NAME, EMAIL, PHONE FROM STUDENTS WHERE STUD_ID=#{studId}
MyBatis執行返回多條結果的SELECT語句查詢
如下所示:
<select id="findAllStudents" resultType="Student"> SELECT STUD_ID AS studId, NAME,EMAIL, PHONE FROM STUDENTS </select>
注意:在這里雖然返回值仍然寫的是Student 但是結果集是個List<Student>類型的集合,mybatis會將查詢到的結果集中的數據,一條條封裝成Student對象,再將這一個個Student對象存入集合中返回
注意,除了List集合類型,也可以使用其他類型的集合類,如Set,Map等。
MyBatis會根據集合的類型,采用適當的集合實現,如下所示:
對於List,Collection,Iterable類型,
MyBatis將返回java.util.ArrayList
如果查詢出多個條數據,resultType指定封裝的類型,那么可以直接將方法的返回值聲明為list集合接收
對於Map類型,
MyBatis 將返回java.util.HashMap
這里注意是返回一個鍵值對,還是多個鍵值對
一個鍵值對---查詢出一條數據:列名做K,值做V,如果查出了多個屬性,就在map中存放了多個K-V對
返回值聲明為HashMap集合接收
多個鍵值對---查詢出多條數據:可以使用List<HashMap<K,V>>存放,一條數據對應一個HashMap
返回值聲明為List<HashMap<K,V>>集合接收
對於Set類型,
MyBatis 將返回java.util.HashSet
對於SortedSet類型
MyBatis將返回java.util.TreeSet -->
結果集映射 resultMap
resultMap被用來將SELECT語句的結果集映射到java對象的屬性中。
在映射文件中,可以先定義出結果集映射resultMap,然后在一些SELECT語句上引用這個resultMap。
MyBatis的結果集映射resultMap非常強大,可以使用它指定sql查詢出的結果集,會被怎么處理並封裝成對象,也可以使用它完成復雜查詢的映射,例如一對一、一對多關系的SELECT語句。
resultMap標簽中的屬性:
id 屬性值在當前名空間內是唯一的。
type屬性值是指定封裝成的類型的全限定名或者是別名。這個屬性要和方法的返回值相同
<resultMap id="StudentResult" type="com.briup.pojo.Student"> <!--<id>子標簽和<result>標簽功能相同,但是<id>用來映射的是表中的主鍵。--> <id property="studId" column="stud_id" /> <!-- <result>子標簽用來將一個resultset列映射到對象的一個屬性中。--> <result property="name" column="name" /> <result property="email" column="email" /> <result property="phone" column="phone" /> </resultMap>
注意1,在<select>標簽中,使用的是resultMap屬性,而不是resultType屬性。
當<select>標簽中配置了resutlMap屬性,MyBatis會根據resutlMap標簽中定義的列名與對象屬性名的 【對應關系】 來自動填充對象中的屬性值。
注意2,resultType和resultMap二者只能用其一,不能同時使用。
resultType屬性指的是結果集將自動封裝成什么類型。這時候默認表中列的名字和類中屬性名字一致。
resultMap 屬性指的是結果集將按照<resultMap>標簽中定義的 【對應關系】 來封裝數據。
最后再次說下sql語句的執行方式
1.通過字符串,調用映射文件中的SQL語句
字符串形式為:
映射文件的namespace + sql語句的id
例如:
SqlSession sqlSession = MyBatisSqlSessionFactory.openSession();
try{
Student student = sqlSession.selectOne("com.briup.mappers.StudentMapper.findStudentById", 1);
System.out.println(student);
}
finally {
sqlSession.close();
}
這種方式容易出錯,因為需要自己編寫字符串,我們需要檢查映射文件中namespace,以及sql語句定義中對參數和返回值的要求,以保證輸入的參數類型和結果返回類型是有效的。-->
2.MyBatis中還可以通過使用映射接口Mapper,調用映射文件中的sql。
sql映射文件中的namespace和映射接口的全限定名要保持一致。
<mapper namespace="com.briup.mappers.StudentMapper">
sql映射文件中的sql語句id值和映射接口中的方法名要保持一致。
sql語句配置的parameterType屬性和映射接口中對應的方法的參數類型保持一致。
sql語句配置的returnType屬性和映射接口中對應的方法的返回值類型保持一致。
<select id="findStudentById" parameterType="int" resultType="Student">
例如:映射接口StudentMapper.java
package com.briup.mappers;
public interface StudentMapper{
Student findStudentById(Integer id);
}
通過映射接口,調用映射文件中的SQL語句。
代碼如下:
SqlSession sqlSession = MyBatisSqlSessionFactory.openSession();
try {
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
Student stu = studentMapper.findStudentById(1);
}
finally {
sqlSession.close();
}