軟件的半成品,解決了軟件開發過程中的普適性問題,從而簡化了開發步驟,提供了開發的效率java
ORM(Object Relational Mapping)對象關係映射,將程序中的一個對象與表中的一行數據一一對應mysql
ORM框架提供了持久化類與表的映射關係,在運行時參照映射文件的信息,把對象持久化到數據庫中git
存在大量的冗餘代碼github
手工建立 Connection、Statement 等web
手工將結果集封裝成實體對象sql
查詢效率低,沒有對數據訪問進行過優化(Not Cache)數據庫
MyBatis本是Apache軟件基金會的一個開源項目iBatis,2010年這個項目由apache software foundation 遷移到了Google Code,而且更名爲MyBatis。2013年11月遷移到Github。MyBatis 是一款優秀的持久層框架,它支持自定義 SQL、存儲過程以及高級映射。MyBatis 免除了幾乎全部的 JDBC 代碼以及設置參數和獲取結果集的工做。MyBatis 能夠經過簡單的 XML 或註解來配置和映射原始類型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 對象)爲數據庫中的記錄apache
官方網站:http://www.mybatis.org/mybatis-3/微信
下載地址:https://github.com/mybatis/mybatis-3/releases/tag/mybatis-3.5.1session
關於對MyBatis的使用,咱們建立的Maven項目是不須要下載MyBatis的,而是能夠經過在Maven項目中的pom文件中添加MyBatis依賴使用!後續我會把MyBatis的開發流程奉上!
File -> NewProject |
---|
![]() |
建立Maven項目 |
![]() |
在pom.xml文件中添加MyBatis核心依賴和MyBatis Log(日誌)依賴
- 核心依賴便是使用MyBatis必備依賴環境,必須導入
- MyBatis Log(日誌)依賴能夠查看MyBatis啓動的過程,便於咱們糾錯、查Bug
注意: 記得把依賴放在<dependecies>標籤內,MyBatis一定是與數據庫交互的,因此也須要導入mysql驅動依賴
<!--MyBatis核心依賴-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!--日誌依賴-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!--MySql驅動依賴-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
建立名爲
mybatis-config.xml
配置文件並配置如下信息注意: 目前mapper.xml默認建議存放在resources中,路徑不能以/開頭,後續我會補全到其餘配置方法
<?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">
<!--MyBatis配置-->
<configuration>
<!--JDBC環境配置、選中默認環境-->
<environments default="MySqlDB">
<!--MySql數據庫環境配置-->
<environment id="MySqlDB">
<!--事務管理-->
<transactionManager type="JDBC"/>
<!--鏈接池-->
<dataSource type="org.apache.ibatis.datasource.pooled.PooledDataSourceFactory">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!-- &轉義& -->
<property name="url" value="jdbc:mysql://localhost:3306/x?useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--Mapper註冊-->
<mappers>
<!--註冊Mapper文件的所在位置-->
<mapper resource="xxxMapper.xml"/>
</mappers>
</configuration>
建立一張表來實現對數據庫的操做
create table tb_user
(
id int auto_increment
primary key,
username varchar(30) null,
password varchar(30) null,
gender char null,
birth date null
) charset = utf8;
這裏我是用的Lombok插件使用註解來完成Getter、Setter方法和無參、有參構造
package com.mylifes1110.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer id;
private String username;
private String password;
private Boolean gender;
private Date birth;
}
定義一個Dao層接口並編寫一個查詢方法
注意: 由於咱們使用MyBatis框架,因此咱們不須要來建立Dao層的實現類了
package com.mylifes1110.dao;
import com.mylifes1110.bean.User;
public interface UserDao {
User selectUserById(int id);
}
MyBatis框架是使用Mapper.xml文件來將對象和sql關係映射的,因此咱們先在resources文件夾中建立一個
UserMapper.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">
<!--namespace:所需實現的接口全限定名-->
<mapper namespace="com.mylifes1110.dao.UserDao">
<!--id:所需重寫的接口抽象方法;resultType:查詢後所需返回的對象類型-->
<select id="selectUserById" resultType="com.mylifes1110.bean.User">
<!--select標籤是查詢標籤,裏面包裹着查詢的sql語句,其中id = #{arg0}是id = ?的意思-->
<!--#{arg0}是指id等於方法中第一個形參,也就是id-->
select id, username, password, gender, birth from tb_user where id = #{arg0}
</select>
</mapper>
將mapper.xml註冊到mybatis-config.xml核心配置中
<!--Mapper註冊-->
<mappers>
<!--註冊Mapper文件的所在位置-->
<mapper resource="xxxMapper.xml"/>
</mappers>
package com.mylifes1110.dao;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
public class UserMapperTest {
@Test
public void selectUserByIdTest() throws IOException {
// 得到讀取MyBatis核心配置文件的流對象
InputStream input = Resources.getResourceAsStream("mybatis-config.xml");
// 根據流對象構建SqlSession鏈接對象的工廠
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(input);
// 經過工廠得到鏈接對象sqlSession
SqlSession sqlSession = factory.openSession();
// 經過鏈接對象得到接口實現類對象
UserDao userDaoImpl = sqlSession.getMapper(UserDao.class);
// 打印結果
System.out.println(userDaoImpl.selectUserById(1));
}
}
package com.mylifes1110.dao;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
public class UserMapperTest {
@Test
public void selectUserByIdTest2() throws IOException {
// 得到讀取MyBatis核心配置文件的流對象
InputStream input = Resources.getResourceAsStream("mybatis-config.xml");
// 根據流對象構建SqlSession鏈接對象的工廠
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(input);
// 經過工廠得到鏈接對象sqlSession
SqlSession sqlSession = factory.openSession();
// 經過鏈接對象直接調用接口中的方法
Object o = sqlSession.selectOne("com.mylifes1110.dao.UserDao.selectUserById", 1);
// 打印結果
System.out.println(o);
}
}
在Maven項目中resources目錄中的配置文件是不會被加載編譯到classes中的,因此若是咱們要將mapper.xml文件放在resources文件夾之外的文件夾就不會被編譯到,以致於咱們的MyBatis使用不了!
問題解決: 爲了解決此問題,咱們能夠在pom.xml文件中聲明mapper.xml文件所在其餘目錄爲resources文件夾,這樣就能夠被編譯到classes文件夾中了!
操做: 在pom.xml文件最後追加< build >標籤,以即可以將xml文件複製到classes中,並在程序運行時正確讀取。
注意: 爲了讓properties文件也被編譯到,也須要在<include>標籤內加入配置文件的路徑,觸類旁通,若是哪一個文件須要被編譯咱們就加標籤便可!
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include><!-- 新添加 */表明1級目錄 **/表明多級目錄 -->
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.xml</include><!-- 新添加 */表明1級目錄 **/表明多級目錄 -->
<include>**/*.properties</include><!--添加properties文件-->
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
目前咱們使用的MyBatis是在覈心配置中寫死了,因此咱們必須藉助jdbc.properties配置文件來加載jdbc,以下操做:
建立jdbc.properties配置文件
#jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/temp?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=123456
修改mybatis-config.xml核心配置文件
<?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">
<!--MyBatis配置-->
<configuration>
<properties resource="jdbc.properties" />
<!--JDBC環境配置、選中默認環境-->
<environments default="MySqlDB">
<!--MySql數據庫環境配置-->
<environment id="MySqlDB">
<!--事務管理-->
<transactionManager type="JDBC"/>
<!--鏈接池-->
<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>
<!--Mapper註冊-->
<mappers>
<!--註冊Mapper文件的所在位置-->
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
關於咱們在寫標籤的時候,每每會寫大量的resultType,可是該屬性須要引入一個類的包路徑,若是加入類型別名就能夠省去寫各類包,只寫類名就能夠。這樣爲實體類定義別名,提升書寫效率
操做: <properties>標籤後面加入以下內容便可使用類型別名
注意: 以下標籤內添加如下配置信息,指定類別名和自動掃描包內類的別名二選一,通常是掃描包的好些,由於定義類會無限定義多個類,很麻煩
<!--定義別名二選一-->
<typeAliases>
<!--定義類的別名-->
<typeAlias type="com.mylifes1110.bean.User" alias="User" />
<!--自動掃描包,將原類名做爲別名-->
<package name="com.mylifes1110.bean" />
</typeAliases>
在開始時候咱們在pom.xml文件中添加了日誌依賴,可是並無使用該日誌依賴。若是使用的話,須要建立一個log4j依賴的配置文件,並配置以下信息
注意: 在配置文中log4j.logger.後面的路徑是dao層接口所在路徑,咱們能夠選擇執行特定的接口來使用日誌功能,也能夠選擇全部的dao層接口都使用日誌功能,這裏我將全部的dao層接口都使用了日誌功能
向pom.xml文件中添加log4j依賴
<!-- log4j日誌依賴 https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
建立並配置log4j.properties
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# MyBatis logging configuration...
log4j.logger.com.mylifes1110.dao=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
日誌信息
級別 | 描述 |
---|---|
ALL LEVEL | 打開全部日誌記錄開關;是最低等級的,用於打開全部日誌記錄。 |
DEBUG | 輸出調試信息;指出細粒度信息事件對調試應用程序是很是有幫助的。 |
INFO | 輸出提示信息;消息在粗粒度級別上突出強調應用程序的運行過程。 |
WARN | 輸出警告信息;代表會出現潛在錯誤的情形。 |
ERROR | 輸出錯誤信息;指出雖然發生錯誤事件,但仍然不影響系統的繼續運行。 |
FATAL | 輸出致命錯誤;指出每一個嚴重的錯誤事件將會致使應用程序的退出。 |
OFF LEVEL | 關閉全部日誌記錄開關;是最高等級的,用於關閉全部日誌記錄。 |
關於註冊Mapper,咱們在上面知識中使用的是單個Mapper註冊。其實咱們能夠選擇一個包來進行註冊全部Mapper.xml文件的,這就須要咱們使用掃描包內全部的Mapper.xml文件。若是咱們使用該方式掃描包內全部Mapper.xml文件,須要遵循以下規則:
- Mapper.xml文件與Dao層接口放在同一包下
- Mapper.xml文件與Dao層接口命名必須保持一致,好比:UserMapper.xml和UserMapper.java
<!--掃描包方式Mapper註冊-->
<mappers>
<!--dao層路徑-->
<package name="com.mylifes1110.dao"/>
</mappers>
關於單一註冊Mapper是以下形式,可是將Mapper文件全都放在了resources文件夾下顯得亂糟糟的,爲了解決這個問題,咱們能夠在resources文件夾下建立一個名爲mappers的文件夾(dir)來存放大量的Mapper.xml文件。那麼問題來了路徑該怎麼寫呢?以下:
<!--Mapper註冊-->
<mappers>
<!--註冊Mapper文件的所在位置-->
<mapper resource="mappers/UserMapper.xml"/>
</mappers>
注意: 在增刪改操做的時候,須要使用sqlSession來提交事務以後才能夠完成增刪改操做
序號參數綁定便是使用
#{arg0}
、#{arg1}
等等代替參數列表中的第一個參數、第二個參數等等。該方法不推薦使用,由於參數的可讀性不好!
// Dao層接口
User selectUserByUserNameAndPassword(String username, String password);
// Mapper.xml
<select id="selectUserByUserNameAndPassword1" resultType="User">
SELECT * FROM t_user
WHERE username = #{arg0} and password = #{arg1}
</select>
註解參數綁定便是使用
@Param("字段")
來代替參數列表中的對應參數,隨後設置好參數在Sql語句中使用#{字段}
來取對應值。該方式推薦使用!
// Dao層接口
User selectUserByUserNameAndPassword(@Param("username") String username, @Param("password")String password);
// Mapper.xml
<select id="selectUserByUserNameAndPassword2" resultType="User">
SELECT * FROM t_user
WHERE username = #{username} and password = #{password}
</select>
Map參數綁定便是使用Map集合來封裝參數,並在方法中傳入一個Map集合,隨後在Sql語句中使用封裝的鍵來取值。該方式瞭解便可,操做繁瑣,不建議使用!
// Dao層接口
User selectUserByUserNameAndPassword(String username, String password);
// 測試類建立Map集合,封裝數據
Map<String, Object> map = new HashMap<>();
// 自定義key,綁定參數
map.put("username", "root");
map.put("password", "123456");
User user = userDao.selectUserByUserNameAndPassword(map);
// Mapper.xml
<select id="selectUserByUserNameAndPassword3" resultType="User">
SELECT * FROM t_user
WHERE username = #{username} and password = #{password} <!-- 經過key得到value -->
</select>
對象參數綁定便是在Dao層接口方法的參數列表中傳入對象,這樣在Sql語句中就能夠隨意取出該對象中的字段值了。由於好多場景須要傳入對象,因此該方式方便簡單,推薦使用!
// Dao層接口
User selectUserByUserNameAndPassword(User user);
// Mapper.xml
<select id="selectUserByUserNameAndPassword4" resultType="User">
SELECT * FROM t_user
WHERE username = #{username} and password = #{password} <!-- 對象中取出的字段值 -->
</select>
查詢標籤: <select id="接口方法名" resultType="返回值類型">
普通查詢既是咱們使用MyBatis查詢單表或多表中的數據
// Dao層接口
User selectUserByUserNameAndPassword(@Param("username") String username, @Param("password")String password);
// Mapper.xml
<select id="selectUserByUserNameAndPassword2" resultType="User">
SELECT * FROM t_user
WHERE username = #{username} and password = #{password}
</select>
可使用count(1)來查詢總數據條數
// Dao層接口
long selectUserCount();
// Mapper.xml
<select id="selectUserCount" resultType="java.lang.Long">
select count(1) from tb_user
</select>
// 測試類
@Test
public void selectUserCount() throws IOException {
InputStream input = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(input);
SqlSession sqlSession = factory.openSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
System.out.println(userDao.selectUserCount());
}
Sql中的模糊查詢在MyBatis中也是可使用的,以下是使用註解參數綁定來模糊查詢的username字段
注意: 查詢List集合,resultType中傳入的也是集中中的泛型對象(特殊)
// Dao層接口
List<User> selectUserListByUsername1(@Param("username") String username);
// Mapper.xml
<select id="selectUserListByUsername1" resultType="com.mylifes1110.bean.User">
select id, username, password, gender, birth
from tb_user
where username like concat('%',#{username},'%')
</select>
// 查詢包含Z的username
@Test
public void selectUserListByUsername1() throws IOException {
InputStream input = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(input);
SqlSession sqlSession = factory.openSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
System.out.println(userDao.selectUserListByUsername1("Z"));
}
<delete id="接口方法名" resultType="返回值類型">
注意: 在刪除標籤中,resultType屬性是能夠省略的,而IDEA快捷鍵生成的<delete>標籤中是默認省略的!
經過id來刪除一個用戶信息
// Dao層接口
int deleteUserById(@Param("id") int id);
// Mapper.xml
<delete id="deleteUserById">
delete from tb_user where id = #{id}
</delete>
<update id="接口方法名" resultType="返回值類型">
注意: 在<update>標籤中也是能夠省略resultType屬性值的
經過id來修改一個用戶信息
// Dao層接口
int updateUserById(User user);
// Mapper.xml
<update id="updateUserById">
update tb_user set
username = #{username}, password = #{password}, gender = #{gender}, birth = #{birth}
where id = #{id}
</update>
<insert id="接口方法名" resultType="返回值類型">
注意: 在<insert>標籤中也是能夠省略resultType屬性值的
新增一個用戶信息
// Dao層接口
int insertUser(User user);
// Mapper.xml
<insert id="insertUser">
insert into tb_user
(username, password, gender, birth)
values
(#{username}, #{password}, #{gender}, #{birth})
</insert>
關於主鍵回填正在學習的你也許不知道什麼意思,可是我分析一個場景,大概你就會了解了!
場景一(int類型主鍵): 在開發中,int類型並自增的主鍵也很常見,可是當你插入一條數據並無插入主鍵id時,Sql會幫你自動添加主鍵id。這就產生了一個弊端,若是咱們想插入一條數據並獲得這個主鍵id時就須要再查一次這條數據獲取主鍵id,顯然這很麻煩。因而,主鍵回填便可解決此問題,當你插入一條數據時,int類型的主鍵id會在insert過程當中單獨查詢一次主鍵並返回該主鍵id,這樣一個處理Sql的操做就作了兩份工做,大大提升了開發效率
場景二(String類型主鍵): 在開發中,與場景一相同,String類型的主鍵一樣很常見,例如:訂單ID一般是一個很長的字符串。而訂單ID是能夠用UUID()方法和replace()方法來獲取的,由於Sql中也是存在這兩個方法的,因此咱們也能夠在插入訂單數據的時候生成訂單ID填入數據庫,一樣也能夠在插入數據後查詢出該訂單ID,這樣也大大提升了我開發效率
<selectKey keyProperty="主鍵字段名" resultType="返回值類型" order="BEFORE | AFTER">
注意: 使用時,將<selectKey>標籤放在<insert>標籤內。after爲後,before爲前。意爲在插入數據以前主鍵回填,在查潤數據以後主鍵回填
last_insert_id()是MySQL內置的一個函數,咱們能夠經過
select last_insert_id()
來查詢出最後一條插入數據的整數int類型ID。經過使用<selectKey>標籤指定order屬性爲after來保證在插入數據以後查詢出該數據的ID
// 表使用的是User表
// Dao層接口
int insertUser(User user);
// Mapper.xml
<insert id="insertUser">
<selectKey keyProperty="id" resultType="int" order="AFTER">
select last_insert_id()<!--適用於整數類型自增的主鍵-->
</selectKey>
insert into tb_user
(username, password, gender, birth)
values
(#{username}, #{password}, #{gender}, #{birth})
</insert>
// 測試類
@Test
public void insertOrder() {
OrderDao orderDao = MyBatisUtils.getMapper(OrderDao.class);
Order order = new Order();
order.setMoney(11.1D);
order.setUserId(2);
System.out.println(orderDao.insertOrder(order));
System.out.println(order.getId());
MyBatisUtils.commit();
}
UUID()和replace()是MySQL內置的兩個內置函數,咱們能夠經過UUID()方法來生成一個UUID字符串,再使用replace()來替換UUID中的「-」,來生成32位的訂單ID字符串,生成訂單ID後經過
SELECT REPLACE(UUID(),'-','')
來查詢出添加到數據庫中的訂單ID
// 建立訂單表
create table tb_order
(
id varchar(32) not null
primary key,
money double null,
user_id int null
) charset = utf8;
// Dao層接口
int insertOrder(Order order);
// Mapper.xml
<insert id="insertOrder" parameterType="com.mylifes1110.bean.Order">
<selectKey keyProperty="id" resultType="string" order="BEFORE">
select replace(UUID(), '-', '')
</selectKey>
insert into tb_order
(id, money, user_Id)
values
(#{id}, #{money}, #{userId})
</insert>
Resource:用於得到讀取配置文件的IO對象,耗費資源,建議經過IO一次性讀取全部所須要的數據。
SqlSessionFactory:SqlSession工廠類,內存佔用多,耗費資源,建議每一個應用只建立一個對象。
SqlSession:至關於Connection,可控制事務,應爲線程私有,不被多線程共享。
將得到鏈接、關閉鏈接、提交事務、回滾事務、得到接口實現類等方法進行封裝。
package com.mylifes1110.utils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.InputStream;
/**
* @ClassName MyBatisUtils
* @Description MyBatis工具類
* @Author Ziph
* @Date 2020/7/11
* @Since 1.8
* @Version 1.0
*/
public class MyBatisUtils {
// 得到SqlSession工廠
private static SqlSessionFactory factory;
// 建立ThreadLocal綁定當前線程中的SqlSession對象
private static final ThreadLocal<SqlSession> tl = new ThreadLocal<SqlSession>();
static {
try {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
factory = new SqlSessionFactoryBuilder().build(is);
} catch (Exception e) {
e.printStackTrace();
}
}
// 得到鏈接(從tl中得到當前線程SqlSession)
private static SqlSession openSession(){
SqlSession session = tl.get();
if(session == null){
session = factory.openSession();
tl.set(session);
}
return session;
}
// 釋放鏈接(釋放當前線程中的SqlSession)
public static void closeSession(){
SqlSession session = tl.get();
session.close();
tl.remove();
}
// 提交事務(提交當前線程中的SqlSession所管理的事務)
public static void commit(){
SqlSession session = openSession();
session.commit();
closeSession();
}
// 回滾事務(回滾當前線程中的SqlSession所管理的事務)
public static void rollback(){
SqlSession session = openSession();
session.rollback();
closeSession();
}
// 得到接口實現類對象
public static <T extends Object> T getMapper(Class<T> clazz){
SqlSession session = openSession();
return session.getMapper(clazz);
}
}