一文入門mybatis

NO IMAGE

先來回顧一下JDBC的使用步驟

  • 導包

spring-mvc
spring-jdbc
ojdbc(oracle) mysql-connector(mysql)
dbcp

  • 添加springmvc配置文件
  • 配置JdbcTemplate
    JdbcTemplate提供了一些方法,用來訪問數據庫
  • 調用JdbcTemplate提供的方法來訪問數據庫,將JdbcTemplate注入到DAO。
      <!-- 配置文件 -->
<util:properties id="config" location="classpath:db.properties"></util:properties>
<!-- 連接池 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="#{config.driver}"></property>
<property name="url" value="#{config.url}"></property>
<property name="username" value="#{config.username}"></property>
<property name="password" value="#{config.password}"></property>
</bean>
<!-- jdbcTemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>

連接過程中,配置文件用util:properties讀取,然後創建DBCP連接池,用spring表達式對裡面的屬性進行賦值,然後創建jdbcTemplate的bean然後給他的dataSource一個連接池的引用

這裡是數據庫連接池配置文件的內容:

    # db.properties
driver=com.mysql.jdbc.Driver
#url=jdbc:mysql://localhost:3306/worktime
url=jdbc:mysql:///worktime
username=root
password=8023
# paramter for BasicDataSource
initSize=1
maxActive=2

DAO層的代碼三個部分,sql,object數組和jdbcTemplate的函數

public void save(Time time)
{
String sql = "INSERT time (date, start, end) VALUES (?,?,?)";
Object[] objects = new Object[] {time.getDate(), time.getStart(), time.getEnd()};
jdbcTemplate.update(sql, objects);
}

下面是查詢所有的代碼

public List<Time> findAll()
{
String sql = "SELECT * FROM time";
List<Time> times = jdbcTemplate.query(sql, new Timemap());
return times;
}

這裡需要有一個類,Timemap(),

class Timemap implements RowMapper<Time>
{
public Time mapRow(ResultSet resultSet, int index) throws SQLException
{
Time time = new Time(resultSet.getString("date"),resultSet.getString("start"),resultSet.getString("end"));
return time;
}
}

這個類需要實現一個接口RowMapper<Time>,然後實現一個函數,mapRow(ResultSet resultSet, int index)這個函數裡面有怎麼把resultset轉化成
對象的過程,然後把這個類傳進jdbcTemplate的方法,在有返回對象列表的時候需要這個參數

下面是查詢一個的代碼

public Time findById(int id)
{
String sql = "SELECT * FROM time WHERE id = ?";
Object[] objects = new Object[] {id};
Time time = jdbcTemplate.queryForObject(sql, objects, new Timemap());
return time;
}

代碼與上面類似,一樣需要那個Timemap()

下面是更新數據的代碼

public void update(Time time, int id)
{
String sql = "UPDATE time set date = ?, start = ?, end = ?";
Object[] objects = new Object[] {time.getDate(), time.getStart(), time.getEnd()};
jdbcTemplate.update(sql, objects);
}

下面是刪除數據的代碼

public void delete(int id)
{
String sql = "DELETE FROM time WHERE id = ?";
Object[] objects = new Object[] {id};
jdbcTemplate.update(sql, objects);
}



mybatis的使用步驟

apache->google->github

開源的持久層框架

編程步驟

  • 導包

mybatis
ojdbc(oracle) mysql-connector(mysql)

  • 添加mybatis配置文件
  • 寫實體類,注意實體類的屬性名和表的字段名一樣,不區分大小寫
  • 映射文件,映射文件寫完之後需要在配置文件中指定位置,並且目錄的分隔符使用 /
  • 調用mybatis提供的SqlSession提供的方法來訪問數據庫

具體如下:

配置文件sqlMapConfig.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>
<environments default="environment">
<environment id="environment">
<!--配置事務管理,採用JDBC的事務管理 -->
<transactionManager type="JDBC"></transactionManager>
<!-- POOLED:mybatis自帶的數據源,JNDI:基於tomcat的數據源 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///worktime"/>
<property name="username" value="root"/>
<property name="password" value="8023"/>
</dataSource>
</environment>
</environments>
<!-- 將mapper文件加入到配置文件中 -->
<mappers>
<mapper resource="entity/timeMapper.xml"/>
</mappers>
</configuration>

mytatis自帶一個數據庫連接池,這裡一樣的配置

然後是實體類

就是包含數據庫中的字段名,屬性名與其一模一樣,設置get/set方法

映射文件

命名規範一般是實體類名字+Mapper

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//ibatis.apache.org//DTD Mapper 3.0//EN"
"http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd">
<mapper namespace="test">
<insert id="insert" parameterType="entity.Time">
INSERT INTO time (date, start, end) VALUES (#{date}, #{start}, #{end})
</insert>
</mapper>

這裡的namesapce確定命名空間,到時候調用的時候可以根據前面的namespace來區分不同表的查詢
然後這個insert標籤裡面,id是這個標籤的名字,唯一性,到時候通過這個id來調用,然後是parameterType,裡面是這個查詢的相應的實體類對應的表
然後就是一條sql語句,和之前的純jdbc以及jdbcTemplate相比,這裡的sql語句還是有區別的,這裡的不再是用?來代表可替換參數,而是直接用spring表達式來讀取類中屬性值

SqlSession的使用來訪問數據庫

	SqlSessionFactoryBuilder sessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sessionFactory = sessionFactoryBuilder.build(Test.class.getClassLoader().getResourceAsStream("sqlMapConfig.xml"));
SqlSession sqlSession = sessionFactory.openSession();
sqlSession.insert("test.insert", new Time("2018-03-24", "18:00:00", "18:00:00"));
sqlSession.commit();
sqlSession.close();

注:上面這句build函數中的參數,是使用系統類加載器來獲取資源

  • 首先獲取SqlSessionFactoryBuilder
  • 通過上一個類的build()方法然後獲取SqlSessionFactory
  • 最後從上一個類的openSession()方法得到SqlSession
  • SqlSession調用相關的方法來訪問數據庫
  • mybatis不會自動提交,增刪改的時候需要手動調用commit函數提交
  • 最後關閉SqlSession

現在添加一個查詢函數,映射文件:

	<select id="findAll" resultType="entity.Time">
SELECT * FROM time
</select>

在查詢的時候,需要的是返回結果的類型,所以這裡的屬性是resultType
在更新的時候,需要的是傳入的參數類型,所以這裡需要的屬性是parameterType

mybatis基本原理

  • SqlSessionFactory在創建的時候需要一個mybatis的配置文件,這個時候讀取這個配置文件,這個配置文件主要包含倆個部分,數據庫連接池和sql語句的映射文件的位置,這裡就包含了sql語句

  • SqlSessionFactory在讀取到這個文件以後,根據數據庫連接和sql語句,創建了許多預編譯的PrepareStatement

      	`PrepareStatement prepareStatement = connection.prepareStatement(sql);`
    

就是類似於以上的這種語句結構,不過這個時候只是有sql語句,還缺少必要的參數
這些prepareStatement被存在Map中,Map中的key的值就是映射文件中的id,而value就是那些prepareStatement

  • 接下來SqlSessionFactory創建了SqlSession
  • 用戶調用SqlSession的函數,參數列表第一個就是映射文件中的id,後面就是訪問數據庫必要的參數
    很明顯,這些就是prepareStatement缺少的參數
  • SqlSession通過id在Map中找到了對應的prepareStatement,然後傳入參數執行這個語句
  • 返回執行結果,如果是查詢,會將記錄轉換成相應的實體對象,因為在創建實體類的時候就需要嚴格要求實體類的屬性名需要和表中的字段名完全一致

增刪改查映射文件部分

<mapper namespace="test">
<insert id="insert" parameterType="entity.Time">
INSERT INTO time (date, start, end) VALUES (#{date}, #{start}, #{end})
</insert>
<select id="findAll" resultType="entity.Time">
SELECT * FROM time
</select>
<select id="findById" parameterType="int" resultType="entity.Time">
SElect * FROM time WHERE id = #{id}
</select>
<update id="update" parameterType="entity.Time">
UPDATE time SET date=#{date}, start=#{start}, end=#{end} WHERE id = #{id}
</update>
<delete id="delete" parameterType="int">
DELETE FROM time WHERE id = #{id}
</delete>
</mapper>
  • 添加的標籤是< insert >
    添加需要的是傳入參數,不需要關心返回類型
  • 查詢的標籤是< select >
    無條件查詢所有只需要關心返回類型,只查詢某一個就需要多一個查詢條件
    如果是數字的話,參數類型的int或者java.lang.Integer
  • 修改的標籤是< update >
    修改的時候,傳入類型,如果需要傳入多個參數,需要有其他方法
  • 刪除的標籤是< delete >
  • 刪除只需要傳入類型即可

返回的不是對象,而直接是一個map

在內部,封裝成對象之前,從數據庫中得到的數據的格式其實就是map,屬性名和屬性值是一個鍵值對,所以這裡可以直接返回一個map,所以這裡可以直接拿到這個中間結果map
這裡用findById的查詢方法來演示:

<select id="findById2" parameterType="int" resultType="map">
SElect * FROM time WHERE id = #{id}
</select>

這裡的改變就是返回類型的地方,不再是實體類,而是map或者java.util.Map,這樣返回的就是一個map
並且在去map裡面的屬性的時候,在oracle中屬性名(key)需要全部大寫,而mysql需要首字母大寫

data.get(“Date”)

##若屬性名和表的字段名不一 樣
(1)取別名
(2)使用resultMap
如果屬性名和表的字段名不一樣,獲取到的結果會只有倆個名字匹配的屬性,其他的屬性值為null
這時候使用結果映射

	<resultMap id="time2Map" type="entity.Time2">
<result property="tdate" column="date"></result>
<result property="tstart" column="start"></result>
<result property="tend" column="end"></result>
</resultMap>

這裡type就是需要轉換的實體類,id唯一,在property中填入實體類的屬性名,然後column填入表中的字段名
寫完之後,回到查詢中,不需要resultType,更換為resultMap,然後名字為那個id

mybatis的mapper映射器(接口)

在開發過程中,需要在持久層創建一個接口,然後用這個接口創建一個實體的持久層對象,在這裡使用映射接口之後,可以省略按個實體類的編寫

映射接口的要求:

  • 接口的方法名稱要和sql配置文件中的id一樣
  • 返回類型要和resultType一樣
  • 參數類型要和paramterType一樣
  • 這個接口的全限定類名需要和sql配置文件的namespace一樣

編程步驟:

  • 編寫一個接口
  • 調用sqlSession的getMapper方法,返回一個持久層對象(映射器要求的對象)
    <mapper namespace="dao.TimeDAO"></mapper>

舉例:
sql配置文件中:

	<select id="findById" parameterType="int" resultType="entity.Time">
SElect * FROM time WHERE id = #{id}
</select>

DAO映射器接口中:

	public Time findById(int id);

測試函數中:

	TimeDAO timeDAO = sqlSession.getMapper(TimeDAO.class);
List<Time> times = timeDAO.findAll();

值得注意的是,如果使用上面提到的resultMap的方法處理表的字段名和類的屬性名不一樣,那麼在映射器中的方法的返回類型需要寫的是resultMap中的type中的類型
還有一個重點,這樣的操作,最後的增改刪還是需要sqlSession.commit()來提交事務

博文是作者原本在其他平臺的,現遷移過來

相關文章

如何寫好年終總結

設計模式之外觀設計模式

Flutter升級1.12適配教程

數據庫中間件分片算法之enum