Mybatis基本運行流程
總結JDBC的問題:
1、數據庫連接創建、釋放頻繁造成系統資源浪費,從而影響系統性能。如果使用數據庫連接池可解決此問題。
2、Sql語句在代碼中硬編碼,造成代碼不易維護,實際應用中sql變化的可能較大,sql變動需要改變java代碼。
3、使用preparedStatement向佔有位符號傳參數存在硬編碼,因爲sql語句的where條件不一定,可能多也可能少,修改sql還要修改代碼,系統不易維護。
4、對結果集解析存在硬編碼(查詢列名),sql變化導致解析代碼變化,系統不易維護,如果能將數據庫記錄封裝成pojo對象解析比較方便。
1.Mybatis介紹
MyBatis是一個支持普通SQL查詢,存儲過程和高級映射的優秀持久層框架。MyBatis消除了幾乎所有的JDBC代碼和參數的手工設置以及對結果集的檢索封裝。MyBatis可以使用簡單的XML或註解用於配置和原始映射,將接口和Java的POJO映射成數據庫中的記錄
mybatis通過xml或註解進行配置,將java對象與sql語句中的參數自動映射生成最終執行的sql語句,並將sql語句執行結果自動映射成java對象,返回給業務層(service)應用。
Mybatis的整體架構:
2.Mybatis的生命週期
正確理解SqlSessionFactory、SqlSessionFactoryBuilder、SqlSession和Mapper的生命週期對於優化Mybatis尤爲重要,這樣可以使Mybatis高效正確完成;同爲重要時Mybatis的生命週期對於理解Myabtis緩存的配置也尤爲重要,我這裏只做簡單的文字介紹(其實也好理解):
(1)SqlSessionFactoryBuilder:作用就是創建一個構建器,一旦創建了SqlSessionFactory,它的任務就算完成了,可以回收。
(2)SqlSessionFactory:作用是創建SqlSession,而SqlSession相當於JDBC的一個Connection對象,每次應用程序需要訪問數據庫,我們就要通過SqlSessionFactory創建一個SqlSession,所以SqlSessionFactory在整Mybatis整個生命週期中(每個數據庫對應一個SqlSessionFactory,是單例產生的)。
(3)SqlSession:生命週期是存在於請求數據庫處理事務的過程中,是一個線程不安全的對象(在多線程的情況下,需要特別注意),即存活於一個應用的請求和申請,可以執行多條SQL保證事務的一致性。
(4)Mapper:是一個接口,它的作用是發送SQL(其中的方法相當於JDBC中的Statement),返回我們需要的結果,或者發送SQL修改數據庫表,所以它存活於一個SqlSession內,是一個方法級別的東西。當SqlSession銷燬的時候,Mapper也會銷燬。
爲什麼SqlSessionFactory是單例的:
SqlSessionFactory是創建SqlSession的工廠,但是創建過程中需要反覆加載全局配置文件,這一點是十分耗時的,爲了優化項目,最好通過單例模式來管理它,使它只能創建一個對象,配置文件加載一次就可以了。(在mybatis整合spring之後,最好的方式是把sqlsessionfactory交給spring來做單例管理)
3.Mybatis的配置
3.1單獨使用Mybatis的配置
1.按照上面的步驟首先定義一個User類
User.java
public class User {
private Integer id;
private String username;
private Integer[] ids;
private List<Integer> idlist;
public Integer[] getIds() {
return ids;
}
public void setIds(Integer[] ids) {
this.ids = ids;
}
public List<Integer> getIdlist() {
return idlist;
}
public void setIdlist(List<Integer> idlist) {
this.idlist = idlist;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + "]";
}
}
2.接着定義一個Mapper接口:定義了一些方法來操作數據庫,方法中具體sql語句的實現在相應的xml文件中。
UserMapper.interface
public interface UserMapper {
/*
* 遵循四個原則:
* 1.方法名和UseMapper.xml中<mapper>標籤中sql標籤的id屬性值相同
* 2.方法的返回值和<mapper>標籤中標籤的resultType屬性值相同
* 3.方法的參數類型和<mapper>標籤中標籤的parameterType屬性值相同
* 4.xml中<mapper>標籤的namespace屬性值和此接口的全類名相同
*/
User findUserById(Integer id);
}
3.接着定義Mapper的映射文件UserMapper.xml,此文件的作用就是映射方法實現具體的SQL語句。
<mapper namespace="Mapper.UserMapper">
<!-- 設置一個sql片段 可以SQL語句中在引用-->
<sql id="selector">
select * from user
</sql>
<select id(方法名)="findUserById" parameterType(方法的參數類型)="Integer" resultType(方法的返回類型)="pojo.User">
<include refid="selector"/>
where id = #{id}
</select>
</mapper>
4.定義了UserMapper和UserMapper.xml之後那麼程序如何才能尋找到呢,通過Mybatis的配置文件。
sqlMapConfig.xml
<configuration>
<!-- 指定加載配置文件 -->
<properties resource="jdbc.properties"/>
<!-- 別名設置 -->
<typeAliases>
<package name="pojo"/>
</typeAliases>
<!-- 和Spring整合後這個標籤就沒用了 -->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事務管理 -->
<transactionManager type="JDBC" />
<!-- 數據庫連接池 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url"
value="jdbc:mysql://localhost:3306/student" />
<property name="username" value="root" />
<property name="password" value="123456" />
</dataSource>
</environment>
</environments>
<!-- 引入User的xml映射文件 我的UserMapper.java
和UserMapper.xml都在Mapper包下-->
<mappers>
<package name="Mapper"/>
<!-- package這種方式需要接口名和xml文件名相同,直接導入包下所有配置文件
-->
</mappers>
</configuration>
5.配置好了配置文件創建一個demo實例來加載配置文件並創建sqlSessionFactory
UserDemo.java
public class UserDemo {
@Test
//通過id查詢值
public void fun() throws IOException{
// 1.加載配置文件
InputStream in = Resources.getResourceAsStream("sqlMapConfig.xml");
// 2.創建SqlSessionFactory
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(in);
// 3.創建sqlSession
SqlSession sqlSession=sqlSessionFactory.openSession();
// 4.sqlSeesion動態創建UserMapper實現類
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 5.實現類調用接口的方法,方法和映射文件一一對應
User user=userMapper.findUserById(1);
System.out.println(user);
}
3.2Mybatis整合Spring
單獨使用Mybatis時我們需要通過加載配置文件來創建SqlsessionFactory,得到sqlsession,然後通過sqlsession來創建mapper接口的代理類,最後通過代理類來執行sql語句。
整合Spring之後,通過在applicationContext.xml中注入兩個類來實現上面所有的操作。原理還是一樣,只不過spring替我們簡化了操作,並且dateSource的操作放在了spring的配置文件中。
applicationContext.xml
context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 將連接池注入容器 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="maxActive" value="10" />
<property name="maxIdle" value="5" />
</bean>
<!--配置工廠 -->
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- 核心配置文件的位置 -->
<property name="configLocation" value="classpath:sqlMapConfig.xml"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 掃描包下的所有接口 -->
<property name="basePackage" value="mapper"/>
<!-- 這裏會自動注入mapper接口
<bean name="userMapper" class="mapper.UserMapper"/>
-->
</bean>
</beans>
這裏的SqlSessionFactoryBean在Spring中最後創建的並不是Bean本身而是sqlSessionFactory
sqlMapConfig.xml文件只需設置一個別名(或者也不設置)
<configuration>
<!-- 設置別名 -->
<typeAliases>
<!-- 2. 指定掃描包,會把包內所有的類都設置別名,別名的名稱就是類名,大小寫不敏感 -->
<package name="pojo" />
</typeAliases>
</configuration>
UserDemo.java
@Test
public void testMapper() throws Exception {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper mapper = ac.getBean(UserMapper.class);
User user = mapper.selectUserById(1);
System.out.println(user);
}
這裏的getBean會創建UserMapper的實現類