之前介紹了一些比較适用的架構,今天來介紹一個持久層架構——MyBatis。
Mybatis 介紹:
架構的作用:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38CXlZHbvN3cpR2Lc1TPB10QGtWUCpEMJ9CXsxWam9CXwADNvwVZ6l2c052bm9CXUJDT1wkNhVzLcRnbvZ2Lc1TPR90dVR0T3VkaNBDOsJGcohVYsR2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2LcRHelR3LcJzLctmch1mclRXY39jN5YTOwgDNwIjNygDM4EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
Mybatis是一個資料持久層架構(dao層),資料持久化,将資料從記憶體中存儲到硬碟中
架構的特點:
Jdbc的缺點:
- 代碼重複性高,反複的建立連接配接
- Sql語句,采用寫死,sql語句寫在java代碼中
- 參數的植入,它跟java的耦合性高
- 結果集的處理非常的麻煩
Mybatis優點:
- 讓程式員隻關注,sql語句不需要去關注對應的代碼
- 幫助我們處理結果集
Mybatis的原名 ibatis
簡單,很靈活,屬于半orm架構,而Hibernate屬于orm架構
Mybatis 快速搭建
- 準備資料庫,在準備實體類
- 配置檔案
- 書寫配置檔案 SqlMapconfig.xml
- 書寫映射檔案 UserMapper.xml
-
<mapper namespace = "test"> <select id = "selectUserById" parameterType="int" resultType="com.hd.pojo.User"> SELECT * FROM t_user WHERE id = #{id} </select>
- 書寫測試代碼MybatisDemo
public void fun() throws IOException {
InputStream in = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession = build.openSession();
Object user = sqlSession.selectOne("test.selectUserById",1);
System.out.println(user);
}
Mybatis環境解釋:
1. 核心配置檔案
命名:命名沒有預設,一般叫做sqlMapConfig
路徑:maven放在resource中
内容:環境:
事務管理器
連接配接池
(獲得和資料庫的連接配接)
讀取映射檔案:
2. 映射檔案
名字 位置,沒有要求 名字:實體類+Mapper.xml(mybatis) 實體類+ .xml(ibatis 命名規範)
Namespace 命名空間, 作用用來區分方法名
兩張表 都有一個查詢的方法, 名字一緻 selectById, 沒辦法區分到底哪個表的操作,namespace這個時候起作用
Sql語句:
<select id = "selectUserById" parameterType="int" resultType="com.hd.pojo.User">
SELECT * FROM t_user WHERE id = #{id}
</select>
id是java代碼中定位到這個語句 parmeterType 參數類型 ResultType傳回值類型
#{id}占位符 id名字可以随意,但是一般和字段名保持一緻
Mybatis結合log4j
1. 導包
Log4j的作用:在控制台上顯示日志
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2. 導入一個檔案
簡單使用mybatis的增删改查:
- 通過id查找使用者
- 通過名字模糊查詢
Mybatis設定參數的方式:
PreparedStatement Statement
Sql注入:
通過用戶端傳入參數的方式,将sql語句注入程式中,這樣的情況就叫sql注入
$ 先把傳過來的參數與SQL語句進行拼接, 形成新的sql語句直接執行整個sql語句, 存在sql注入風險
# 占位符 先把寫好的sql語句進行預編譯,再将參數設定進來。自動檢查參數中是否包含sql語句,如果包含就執行失敗, 避免了sql語句注入
建議全部使用#{}占位符的方式.
配置映射檔案:
<select id="selectUserByName" parameterType="string" resultType="com.hd.pojo.User">
SELECT * FROM t_user WHERE name LIKE "%"#{name}"%"
</select>
測試代碼:
public void fun1(){
String name = "張";
List<Object> users = sqlSession.selectList("test.selectUserByName", name);
System.out.println(users);
}
- 增加使用者
如果是增删改操作,必須是送出事務,最終才會對資料庫進行修改。
1. 修改使用者
Update
2. 删除使用者
Delete
在插入一條資料之後,馬上要根據這條資料向另外一張表中插入資料
主鍵生成政策:
代理主鍵:
自動遞增:
在資料庫中的機制:再生成新的資料之前,先生成記錄再出插入主鍵
KeyProperty 代表的是對象的屬性名
resultType 查出來主鍵的類型
order 排序如果是自動遞增就用after 如果是uuid 就用before
<selectKey keyProperty="id" resultType="int" order="AFTER">
SELECT LAST_INSERT_ID()
</selectKey>
Uuid:
機制:在生成主鍵,再去生成記錄,如果采用uuid機制,在設計資料庫的時候長度必須大于等于36
<selectKey keyProperty="id" resultType="int" order="BEFORE">
Select uuid()
</selectKey>
自然主鍵
原始dao層開發
SqlSessionFactoryBuilder 讀取配置檔案,調用他的build
SqlSessionFactory 建立SqlSession
SqlSession 封裝了方法(在每個方法中都重新建立,建議使用局部變量)
Dao依賴于SqlSessionFactory
public class UserDaoImpl implements UserDao {
private SqlSessionFactory sqlSessionFactory;
public UserDaoImpl(SqlSessionFactory sqlSessionFactory){
this.sqlSessionFactory = sqlSessionFactory;
}
public User selectUserById(Integer id) {
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = sqlSession.selectOne("test.selectUserById",id);
return user;
}
}
代理dao(Mapper接口)開發
前提條件
1.接口的名字建議和映射檔案的名字保持一緻
Namespace 必須和接口的相對路徑名保持一緻
2. 在配置檔案中的resultType必須和接口中的方法名的傳回值類型保持一緻
3,.配置檔案中的參數類型,必須和接口中的參數的類型保持一緻
4.配置檔案中的id必須和接口中的方法名保持一緻
注意:方法中的參數隻能有一個
selectOne selectList是根據mapper中的方法傳回值的類型決定的
sqlMapconfig檔案詳解
配置檔案中的屬性順序不能更改必須按照上面的順序
typteAliases 别名
<typeAliases>
<!--<typeAlias alias="User" type="com.hd.pojo.User"/>-->
<package name="com.hd.pojo"></package>
</typeAliases>
package 自動為實體類起兩個别名 一個是類名
一個是類名首字母小寫
比如 com.hd.pojo.User User/user
typeHandlers類型轉換器
實作jdbc(資料庫中的類型) 和 java的類型的轉換,一般情況下不需要自己去改,有一些特殊情況,需要手動映射
輸入類型和輸出類型
輸入類型
普通類型:
還能使用pojo類型
Pojo的封裝類:
既包含普通類型也包含其他的類型,在mapper中所有的方法的參數都不需要去考慮,把真正的參數放到封裝類中,并添加get/set方法,配置檔案要采用ognl表達式的方式去取值
Map
輸出類型:
ResultType
自動轉換,名字保持一緻才會自動轉換
ResultMap:
手動轉換,如果名字不一緻不會轉換,需要手動轉換
<mapper namespace = "com.hd.resultMap.UserMapper">
<resultMap id="selectUser" type="com.hd.pojo.User">
<result property="password" column="psd"></result>
</resultMap>
<select id = "selectUserById"
parameterType="com.hd.queryVo.QueryVo"
resultType="selectUser">
SELECT * FROM t_user WHERE id = #{id}
</select>
ResultMap 不能用resultType
裡面的值是其他地方定義的resultMap中的id值
ResultMap :type 将轉化的類型
Id: 主鍵 property(類中的屬性名) column(資料庫字段名) JavaType jdbcType TypeHandler
Result 普通屬性
動态SQL
if标簽
<if test="id != '' and id != null">
and id = #{id}
</if>
Test 使用ognl表達式的發方法取值 可以if條件
并且 and
或者 or
如果有多個條件,不知道是第一個成立and的位置不好放,就在任何一個位置都可能會出異常,使用where标簽解決
Where标簽
能夠自動去除 前and
如果所有的條件都不成立,那麼where關鍵字自動去除
Foreach 标簽
<foreach collection="array" open="(" close=")" separator="," item="id">
#{id}
</foreach>
Collection 用來識别是什麼資料類型
數組: array
List集合: list
Set集合: set
封裝類: 必須是封裝類中的屬性名
Open 在周遊數組前的sql語句
Close 周遊之後再加上一段sql語句
Separator 周遊數組,每個元素之間的分隔符
Item 周遊時給目前元素起的名字,必須和占位符中的名字保持一緻
Index 下标
Sql 片段
<sql id="select">
SELECT sex,address,name
</sql>
<include refid="select"></include>
Include refid 屬性對應就是sql片段中的id 名
多表查詢
1對1查詢
實作1對1查詢的結果集的封裝
兩種方法:
建立一個實體類,實體類中包含所有想要轉化的列名
可以建一個類,讓這個類去繼承一個類
ResultMap
在原來的實體類中增加一個另外一個實體類類型的屬性,并添加get set方法,在結果集處理的時候采用ResultMap
ResultMap中<association>代表的是一對一關聯查詢
注意:如果字段名和屬性不寫轉化,就不會轉化,想要将查詢到的結果全部封裝到實體類中就必須全部都寫
1對多查詢
resultType
建立一個實體類,實體類中包含所有想要轉化的列名
可以建一個類 讓這個類去繼承一個類
ResultMap
添加屬性 集合 并且添加get/set方法
<resultMap id="companyView" type="Company">
<id property="id" column="companyId"></id>
<result property="name" column="companyName"></result>
<collection property="users" javaType="list" ofType="User">
<id property="id" column="id"></id>
<result property="name" column="name"></result>
<result property="sex" column="sex"></result>
<result property="password" column="password"></result>
<result property="address" column="address"></result>
</collection>
</resultMap>
Collection property 是實體類的屬性名,javaType(集合 list set)
ofType 封裝集合中每個元素的類型
緩存(Redis Memache)
延遲加載
逆向工程
逆向工程:通過一方生成另一方
hibernate auto屬性 update 自動根據你的配置檔案生成表
mybatis
根據表自動建立 實體類 接口類 映射檔案
使用maven實作逆向工程
1 mysql驅動, 配置檔案中将你本地的mysql資料庫驅動的絕對路徑改掉
2 資料庫名 使用者名 密碼
3 改變生成 實體類 映射檔案 mapper 的生成路徑(可選)
4 改資料庫表名 實體類名 注意實體類名千萬不能重複
注意點選插件運作的時候:點一次
Spring 整合 mybatis
spring 管理對象
SqlSessionFactory
sqlSession
- 導包
spring 所有包
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
mybatis 所有包
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
整合包
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
資料庫驅動包
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.37</version>
</dependency>
日志包
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>