Spring學習手冊(12)—— Spring JDBC數(shù)據(jù)庫訪問我們學習了如何使用Spring的JDBC抽象進行數(shù)據(jù)庫訪問涩盾,這極大的簡化了開發(fā)者的工作量:不需要關心數(shù)據(jù)庫連接、關閉蚀之;查詢語句的構(gòu)造闽烙、執(zhí)行......但我們依然需要使用?
來占空查詢參數(shù)翅睛、解析查詢返回結(jié)果集。本文我們就來學習對象關系映射(Object Relational Mapping (ORM))訪問數(shù)據(jù)庫黑竞。本文主要學習當下較為流行的mybatis框架捕发。
一、mybatis簡介
MyBatis 是支持定制化 SQL很魂、存儲過程以及高級映射的優(yōu)秀的持久層框架扎酷。MyBatis 避免了幾乎所有的 JDBC 代碼和手動設置參數(shù)以及獲取結(jié)果集。MyBatis 可以對配置和原生Map使用簡單的 XML 或注解遏匆,將接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java對象)映射成數(shù)據(jù)庫中的記錄法挨。
在2.0版本之前谁榜,該框架叫ibatis,后3.0版本更名為mybatis凡纳。由于Spring官方只整合了ibatis2窃植,mybati社區(qū)為在Spring中支持mybatis,創(chuàng)建了mybatis-spring子項目使mybaits無縫的整合到Spring中去。
二惫企、引入相關jar包依賴
Spring項目整合mybatis框架需要依賴mybatis和mybatis-spring jar包撕瞧,因此我們需要首先添加該依賴。build.gradle文件依賴項修改如下:
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.11'
compile 'mysql:mysql-connector-java:6.0.6'
compile 'org.mybatis:mybatis:3.4.2'
compile 'org.mybatis:mybatis-spring:1.3.1'
compile 'org.springframework:spring-jdbc:4.3.6.RELEASE'
compile 'org.springframework:spring-context:4.3.6.RELEASE'
}
這里mybatis版本號為3.4.2狞尔,mybatis-spring版本號為1.3.1丛版。IDEA會自動編譯項目下載依賴jiar包,當然你也可以在項目根目錄下運行如下命令編譯(已將gradle添加到path目錄):
gradle build
三偏序、spring整合mybatis實戰(zhàn)
我們添加了相關Jar包的依賴页畦,本節(jié)我們就來展示如何在Spring中整合mybatis。
在開始代碼實例之前研儒,我們首先新建數(shù)據(jù)庫score_manager(數(shù)據(jù)庫名可任意命名豫缨,但需保持dataSource中URL配置根數(shù)據(jù)庫名一致)、新建數(shù)據(jù)表student端朵,表結(jié)構(gòu)如下:
列名 | 類型 |
---|---|
id | int |
name | varchar(20) |
gender | char(1) |
age | int |
同時我們創(chuàng)建Student領域模型如下:
public class Student {
private int id;
private String name;
private String gender;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString(){
return "["+id+"好芭,"+name+","+gender+","+age+"]";
}
}
3.1 創(chuàng)建SQL查詢映射文件
<?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.liangwei.learnspring.dao.StudentMapper">
<resultMap id="student" type="com.liangwei.learnspring.domain.Student">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="gender" column="gender"/>
<result property="age" column="age"/>
</resultMap>
<select id="getStudentNums" resultType="int">
select count(*) from student
</select>
<select id="getStudentById" resultMap="student">
select * from student where id=#{studentId}
</select>
<insert id="insertStudent" parameterType="com.liangwei.learnspring.domain.Student">
insert student
(id,name,gender,age)
values(
#{id},
#{name},
#{gender},
#{age})
</insert>
<delete id="deleteStudent" parameterType="int">
delete from student where id = #{studentId}
</delete>
<update id="updateStudent" parameterType="com.liangwei.learnspring.domain.Student">
update student set gender = #{gender} where id = #{id}
</update>
</mapper>
我們使用mapper
標簽創(chuàng)建映射文件,并且使用namespace
屬性指定該mapper的命名空間冲呢,這里我們將命名空間設定為com.liangwei.learnspring.dao.StudentMapper,舍败,之所以如此設置會在后面進行講解。
我們使用resultMap
標簽定義了一個返回結(jié)果集的映射關系敬拓,其中id
和result
內(nèi)部標簽都是表示返回對象和數(shù)據(jù)庫某列的映射關系邻薯,id
指代數(shù)據(jù)庫的表主鍵,提升mybatis運行效率乘凸。property
屬性表示定義領域?qū)ο蟮膶傩悦Q厕诡,column
屬性指定了數(shù)據(jù)表中的列名。定義好resultMap
营勤,mybatis就會自動為我們完成結(jié)果集和領域?qū)ο笾g的互相轉(zhuǎn)換灵嫌。
我們分別使用insert
、delete
葛作、select
寿羞、update
來定義增刪查改語句,id
用于唯一表示該語句进鸠,parameterType
指向該語句可接受的參數(shù)稠曼,resultMap
屬性設置為前面使用resultMap
標簽設置的id值,mybatis就會自動將查詢結(jié)果進行映射。
3.2 定義DataSource
<!--datasource 定義-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/score_manager"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
3.3 定義SqlSessionFactoryBean
在 MyBatis-Spring 中,我們使用SqlSessionFactoryBean來創(chuàng)建Session工廠霞幅,配置信息如下:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations" value="classpath:mapper/*Mapper.xml"/>
</bean>
dataSource
屬性為前面已經(jīng)配置完成的DataSource漠吻,mapperLocations
屬性指向我們配置的SQL映射文件,這里我們設置為classpath路徑下mapper文件夾下的所有以Mapper命名結(jié)尾的XML文件司恳。
3.4 使用SqlSessionTemplate
SqlSessionTemplate類是 MyBatis-Spring 的核心途乃。 這個類負責管理 MyBatis 的 SqlSession, 調(diào)用 MyBatis 的 SQL 方法, 翻譯異常。 SqlSessionTemplate 是線程安全的, 可以被多個 DAO 所共享使用扔傅。
SqlSessionTemplate 實現(xiàn)了 SqlSession 接口,我們使用它來定義sqlSession,配置方式如下:
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
</bean>
其中構(gòu)造器參數(shù)傳入配置好的sqlSessionFactory
耍共。
定義StudentDAO,接口定義如下:
public interface StudentDAO {
Student getStudentById(int studentId);
int getStudentNums();
void insertStudent(Student student);
void deleteStudent(int studentId);
void updateStudent(Student student);
}
接口方法命名自解釋猎塞,這里就不再對每個方法的意義進行解釋试读。
對StudentDAO方式實現(xiàn)如下:
public class StudentDAOImpl implements StudentDAO{
private SqlSession sqlSession;
public Student getStudentById(int studentId) {
return sqlSession.selectOne("getStudentById",studentId);
}
public int getStudentNums() {
return sqlSession.selectOne("getStudentNums");
}
public void insertStudent(Student student) {
sqlSession.insert("insertStudent",student);
}
public void deleteStudent(int studentId) {
sqlSession.delete("deleteStudent",studentId);
}
public void updateStudent(Student student) {
sqlSession.update("updateStudent",student);
}
public void setSqlSession(SqlSession sqlSession) {
this.sqlSession = sqlSession;
}
}
該實現(xiàn)持有SqlSession類型的私有屬性,我們使用set方法進行注入荠耽,XML配置方式如下:
<bean id="studentDao" class="com.liangwei.learnspring.dao.impl.StudentDAOImpl">
<property name="sqlSession" ref="sqlSession"/>
</bean>
以上我們使用SqlSessionTemplate完成了Spring中整合mybatis的工作钩骇,我們?yōu)槊糠N領域?qū)ο蟮牟僮鞫xDAO接口并實現(xiàn),我們需要為所有的DAO實現(xiàn)注入sqlSession铝量。
3.5 使用SqlSessionDaoSupport(簡單點)
我們使用SqlSessionTemplate極大的簡化了我們對SQL的操作倘屹,但是我們依然需要為每一個實現(xiàn)類添加setter注入方法,當然我們可以定義基類然后讓所有的DAO實現(xiàn)繼承該基類慢叨,然后使用Spring提供的自動注入簡化代碼量纽匙。本節(jié)我們學習使用SqlSessionDaoSupport類,它相當于封裝了SqlSessionTemplate的基類拍谐,我們只需要使用getSqlSession()
來獲取一個SqlSessionTemplate
,剩下的操作就和SqlSessionTemplate的調(diào)用相同了烛缔。
定義StudentDAOSupport接口:
public interface StudentDAOSupport {
Student getStudentById(int studentId);
int getStudentNums();
void insertStudent(Student student);
void deleteStudent(int studentId);
void updateStudent(Student student);
StudentDAOSupport接口實現(xiàn):
public class StudentDAOSupportImpl extends SqlSessionDaoSupport implements StudentDAOSupport {
public Student getStudentById(int studentId) {
return getSqlSession().selectOne("getStudentById",studentId);
}
public int getStudentNums() {
return getSqlSession().selectOne("getStudentNums");
}
public void insertStudent(Student student) {
getSqlSession().insert("insertStudent",student);
}
public void deleteStudent(int studentId) {
getSqlSession().delete("deleteStudent",studentId);
}
public void updateStudent(Student student) {
getSqlSession().update("updateStudent",student);
}
}
XML配置提供id為studentDaoSupport的bean:
<bean id="studentDaoSupport" class="com.liangwei.learnspring.dao.impl.StudentDAOSupportImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
SqlSessionDaoSupport 需要一個 sqlSessionFactory 或 sqlSessionTemplate 屬性來 設 置 。 以上我們使用顯式的方式設置sqlSessionFactory
屬性赠尾,SqlSessionDaoSupport
會使用sqlSessionFactory
來創(chuàng)建一個SqlSessionTemplate
實例力穗,當然我們也可以使用Spring的自動注入來省去配置代碼毅弧。 如 果 兩 者 都 被 設 置 了 , 那 么 SqlSessionFactory 是被忽略的气嫁。
3.6 注入映射器(再簡單點)
SqlSessionTemplate
和SqlSessionDaoSupport
已明顯的減少了我們關于數(shù)據(jù)操作的代碼量寸宵,而mybatis提供了映射器方式,為進一步減少代碼量提供了支持。mybatis使用代理類為我們簡化了具體的接口實現(xiàn)代碼七扰。
定義映射器接口:
public interface StudentMapper {
Student getStudentById(int studentId);
int getStudentNums();
void insertStudent(Student student);
void deleteStudent(int studentId);
void updateStudent(Student student);
}
配置映射器,使mybatis完成映射器注入:
<bean id="studentMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.liangwei.learnspring.dao.StudentMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
我們使用org.mybatis.spring.mapper.MapperFactoryBean
定義名為studentMapper
的bean。需要為該bean提供mapperInterface
和sqlSessionFactory
屬性锐膜。sqlSessionFactory
我們已多次使用,這里就不過多贅述捞奕;mapperInterface
為我們定義的映射器接口(一般命名使用Mapper結(jié)尾)恨搓,上面例子中就是我們定義的StudentMapper
接口斧抱。
這樣mybatis會自動為該映射器接口創(chuàng)建代理,并關聯(lián)相關的SQL文件定義(我們在定義sqlSessionFactory
時已經(jīng)明確制定要加載的SQL映射文件位置)掂恕。只需這樣兩步乎串,我們完成了映射器接入工作鸯两。
??如果你對我們前面定義的SQL映射文件還有印象鸠匀,應該還記得mapper
標簽下有個namespace
屬性缀棍,我們設置為com.liangwei.learnspring.dao.StudentMapper
,當時之所以如此設置就是為了使其支持映射器方式(目前SqlSessionTemplate
和SqlSessionDaoSupport
方式并沒有強制限制該namespace屬性),如果namespace屬性設置與映射器接口完全限定名不同,則會報方法為找到等類型錯誤哑诊。
更簡單點
當我們需要配置多個映射器時缴饭,按照以上方式的配置也是會花費較多的時間精力担猛,mybatis為我們提供了更方便的方式:使用MapperScannerConfigurer配置智嚷。它會在類路徑下查找映射器稍浆,并將它們創(chuàng)建為MapperFactoryBean。
配置方式:
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.liangwei.learnspring.dao" />
</bean>
這樣它會為dao包名下的所有映射器類創(chuàng)建為MapperFactoryBean。當然在現(xiàn)實項目實踐中,我們一般將包名命名為mapper結(jié)尾陪竿,如上我們可以改成com.liangwei.learnspring.dao.mapper
闰挡,這樣更方便我們閱讀并理解維護代碼。當我們需要設置多個包路徑時礁哄,我們可以使用分號或逗號進行分割解总。
3.7 代碼測試
以上我們使用不同的三種方式整合Spring和mybatis,我們定義了名為studentDao
姐仅、studentDaoSupport
花枫、studentMapper
的三個bean,我們可以獲取它們并直接使用它們的方法掏膏,測試代碼如下:
public class Application {
public static void main(String[] args){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("dao.xml");
/* 獲取bean */
StudentDAO studentDAO = applicationContext.getBean("studentDao", StudentDAO.class);
/* 獲取學生數(shù)量 */
System.out.println(studentDAO.getStudentNums());
/* 查找學生ID為1 的學生信息*/
System.out.println(studentDAO.getStudentById(1));
Student student = new Student();
student.setId(3);
student.setName("Jane");
student.setGender("F");
student.setAge(20);
/* 插入新數(shù)據(jù) */
studentDAO.insertStudent(student);
/* 查詢新插入的數(shù)據(jù)劳翰,ID=3 */
System.out.println(studentDAO.getStudentById(3));
student.setGender("M");
/* 更新學生數(shù)據(jù)信息,將性別改為M */
studentDAO.updateStudent(student);
System.out.println(studentDAO.getStudentById(3));
/*刪除studentID為3 的學生信息*/
studentDAO.deleteStudent(3);
/* SqlSessionDaoSupport使用 */
StudentDAOSupport studentDAOSupport = applicationContext.getBean("studentDaoSupport", StudentDAOSupport.class);
System.out.println(studentDAOSupport.getStudentNums());
System.out.println(studentDAOSupport.getStudentById(1));
student.setGender("F");
studentDAOSupport.insertStudent(student);
System.out.println(studentDAOSupport.getStudentById(3));
student.setGender("M");
studentDAOSupport.updateStudent(student);
System.out.println(studentDAOSupport.getStudentById(3));
studentDAOSupport.deleteStudent(3);
/* StudentMapper */
StudentMapper studentMapper = applicationContext.getBean("studentMapper", StudentMapper.class);
System.out.println(studentMapper.getStudentNums());
System.out.println(studentMapper.getStudentById(1));
student.setGender("F");
studentMapper.insertStudent(student);
System.out.println(studentMapper.getStudentById(3));
student.setGender("M");
studentMapper.updateStudent(student);
System.out.println(studentMapper.getStudentById(3));
studentMapper.deleteStudent(3);
}
}
如上我們對每種方式的沒種接口方法進行了調(diào)用馒疹,代碼較為簡單且結(jié)合注釋很容易理解佳簸,這里我們就不更進一步解釋了。
運行上述代碼颖变,我們會在控制臺得到如下信息輸出:
2 //數(shù)據(jù)庫中學生個數(shù)
[1生均,Jone,F,20] //查詢studentId為1 的學生信息
[3,Jane,F,20] //插入studentId為3的學生信息后的查詢結(jié)果
[3腥刹,Jane,M,20]//更新了studentId為3的學生信息后的查詢結(jié)果:性別更改為M
2
[1马胧,Jone,F,20]
[3,Jane,F,20]
[3衔峰,Jane,M,20]
2
[1佩脊,Jone,F,20]
[3蛙粘,Jane,F,20]
[3,Jane,M,20]
為方便理解輸出信息威彰,我們在輸出信息上加了些注釋出牧,結(jié)合測試代碼和注釋可以更方便的理解輸出結(jié)果。
代碼下載
四歇盼、總結(jié)
本文我們完成了在Spring框架下mybatis的引入和整合舔痕,我們借助mybatis-spring
項目使用三種不同的方式(SqlSessionTemplate
、SqlSessionDaoSupport
和映射器
)完成整合工作豹缀。通過以上一步步的操作我們已經(jīng)體會到mybatis的簡便性赵讯、易操作性,它拆分了SQL語句和項目代碼接口的依賴耿眉,減輕繁瑣的數(shù)據(jù)庫模版代碼操作边翼,極大的提升了程序開發(fā)人員工作效率。
完成Spring框架內(nèi)整合mybatis后鸣剪,我們剩下的主要工作就是定義DAO或Mapper接口组底,編寫映射器的XML文件,mybatis官網(wǎng)已經(jīng)給出來了較為詳細的文檔筐骇,大家可以到官網(wǎng)查看文檔學習债鸡,這里也不打算寫關于XML文件編寫方便的語法文章了。