MyBatis 是支持普通 SQL 查詢,存儲過程和高級映射的優(yōu)秀持久層框架励背。MyBatis 消除 了幾乎所有的 JDBC 代碼和參數(shù)的手工設(shè)置以及結(jié)果集的檢索俄精。MyBatis 使用簡單的 XML 或注解用于配置和原始映射,將接口和 Java 的 POJOs(Plan Old Java Objects,普通的 Java 對象)映射成數(shù)據(jù)庫中的記錄朦拖。
MyBatis的前身是iBatis,MyBatis在iBatis的基礎(chǔ)上面侯养,對代碼結(jié)構(gòu)進行了大量的重構(gòu)和簡化;大量的參考了Hibernate的設(shè)計
MyBatis沒有hibernate方便,功能沒有hibernate強大;易學(xué),性能更好的被程序猿控制
1.導(dǎo)jar包:
MyBatis的核心包:mybatis-3.1.1.jar
MyBatis依賴的jar包:lib/*.jar
MySQL的驅(qū)動包:mysql-connector-java-5.1.7-bin.jar
2.在數(shù)據(jù)庫(mybatis)中創(chuàng)建一張表(user)
3.根據(jù)表創(chuàng)建實體類:User
4.MyBatis的主配置文件:mybatis-config.xml
配置事務(wù)管理器/連接池/映射器
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">
<configuration>
<!-- 聲明一些屬性Properites
<properties>
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybatis"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</properties>
-->
<properties resource="db.properties" />
<!-- 為類型配置別名 -->
<typeAliases>
<typeAlias type="com.jd.pss.query.User" alias="User"/>
<typeAlias type="com.jd.pss.query.UserQueryObject" alias="UserQueryObject"/>
</typeAliases>
<!-- 配置環(huán)境
default代表mybatis默認(rèn)使用哪個環(huán)境
問題,mybatis可以配置多個數(shù)據(jù)庫環(huán)境,目的是什么?
1,容易在不同數(shù)據(jù)庫之間切換(default)
2,mybatis是天生支持多數(shù)據(jù)庫,多數(shù)據(jù)庫類型的持久化框架;
-->
<environments default="default">
<!-- 配置一個環(huán)境,每個環(huán)境有自己的id-->
<environment id="default">
<!-- transactionManager:事務(wù)管理器,在定義這個環(huán)境中應(yīng)該怎么使用事務(wù)
JDBC:注意大小寫,JDBC一定是一種Mybatis里面定義的TranscationManager的類型的別名;代表使用JDBC的事務(wù)管理
-->
<transactionManager type="JDBC" />
<!-- datasource:數(shù)據(jù)庫連接池,定義在這個環(huán)境中連接數(shù)據(jù)庫相關(guān)信息
POOLED:注意大小寫,POOLED也一定是一種mybatis里面定義的DataSource的別名,是代表需要緩存的連接池
-->
<dataSource type="POOLED">
<!-- 使用property元素對數(shù)據(jù)庫連接信息進行配置 -->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!-- 在完成映射文件之后,需要告訴mybatis -->
<mappers>
<mapper resource="com/jd/pss/query/UserMapper.xml"/>
</mappers>
</configuration>
** 5.MyBatis的映射文件**
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">
<!-- mapper節(jié)點上的namespace屬性
namespace:命名空間,默認(rèn)情況下,這個namespace可以隨意寫,只是要求不同mapper文件之間的namespace不要重復(fù);
-->
<mapper namespace="com.jd.pss.UserMapper">
<!-- 聲明一個resultMap來對結(jié)果集到對象的映射規(guī)范
type屬性:這個resultMap要返回的對象類型
id屬性:為這一個resultMap起一個名字
-->
<resultMap type="User" id="base_mapping">
<!-- 設(shè)置一個id屬性,
column:對應(yīng)的列名;
property:對應(yīng)對象中的屬性名
javaType:對應(yīng)的java類型;
jdbcType:對應(yīng)的數(shù)據(jù)庫中的類型;javaType+jdbcType=====hibernate的<property元素中的type
默認(rèn)情況下一般不需要設(shè)置jdbcType和javaType,mybatis會自動識別
-->
<id column="id" property="id"/>
<!-- 使用result來映射普通屬性 -->
<!-- 普通的屬性映射 -->
<result column="name" property="name"/>
<result column="salary" property="salary"/>
<result column="hiredate" property="hiredate"/>
</resultMap>
<resultMap type="User" id="select_list_mapping">
<id column="id" property="id"/>
<result column="name" property="name"/>
</resultMap>
<!-- 元素上都有一個id屬性,這個id屬性唯一的在這個mapper文件中定義了這個元素的名字
這個元素的全名:namespace.id
mybatis的CRUD操作元素中,寫的是SQL
keyColumn:代表主鍵的列名;
keyProperty:代表在對象中表示OID的屬性名字
useGeneratedKeys:采用JDBC的獲取自動生成主鍵的方式獲取主鍵
-->
<insert id="add" parameterType="User" keyColumn="id" keyProperty="id" useGeneratedKeys="true">
<!-- 在SQL中使用#{}來對應(yīng) parameterType中的對應(yīng)屬性的值-->
INSERT INTO user(name,hiredate,salary)
VALUES (#{name},#{hiredate},#{salary})
</insert>
<!-- 添加一個update節(jié)點 -->
<update id="update" parameterType="User">
update user set name=#{name},salary=#{salary},hiredate=#{hiredate} where
id=#{id}
</update>
<!-- 添加一個刪除節(jié)點
<delete id="delete" parameterType="com.jd.mybatis.User">
注意,這個時候,#{id}中id指的是傳入的User實例中的id屬性值
DELETE FROM user WHERE id = #{id}
</delete>
-->
<delete id="delete" parameterType="long">
<!-- 注意,如果傳入的參數(shù)值是一個普通類型,那么在SQL中,就隨便寫名字 -->
DELETE FROM user WHERE id = #{id}
</delete>
<!-- 在mybatis里面是不區(qū)分get和select的,get僅僅就是一個select
1,resultType:查詢出來的結(jié)果集中每一行結(jié)果集要包裝成的對象
2,這里面會有一個問題,列和對象的屬性是怎么對應(yīng)的呢?
可以使用resultMap來自定義列和對象屬性的映射關(guān)系;
[注意]:一個select只能有一個resultType或者一個resultMap
-->
<!-- 編寫查詢語句 -->
<select id="get" parameterType="Long"
resultMap="base_map">
select *from user where id=#{id}
</select>
<select id="list" resultMap="base_map">
select *from user
</select>
</mapper>
測試類
查詢測試類
監(jiān)控MyBatis的運行
Domain的修改|刪除|查詢操作
mybatis找參數(shù)的方式:
1.首先使用屬性名的方式去找
必須:保存操作傳入的是一個User對象,所以在SQL中的#{name},的name使用的是User對象中的屬性名
2.如果在傳入的類型中找不到對應(yīng)的屬性,必如刪除操作,傳入的是一個long類型,在long中找不到一個叫做id的屬性,此時就直接使用傳進來的值作為參數(shù)
MyBatis的運行流程:
1.加載配置文件:mybatis-config.xml
得到事務(wù)管理器,使用JDBC的事務(wù)管理器來管理事務(wù)
得到連接池對象,然后設(shè)置相關(guān)的屬性,創(chuàng)建出對應(yīng)的連接池:POOLED,mybatis自身提供的連接池
創(chuàng)建一個SqlSessionFactory對象(相當(dāng)與一個連接池)
2.打開一個會話(和數(shù)據(jù)庫的會話) SqlSession,相當(dāng)于一個連接對象:Connection
3.使用SqlSession中的方法獲取到映射文件中的SQL語句,并且執(zhí)行SQL,獲取到執(zhí)行的結(jié)果
namespace+sqlid
insert into user(name, salary, hiredate) values(#{name},#{salary},#{hiredate})
將SQL中的占位符翻譯成符合預(yù)編譯語句對象的SQL :帶有占位符
insert into user(name, salary, hiredate) values(?,?,?)
創(chuàng)建一個預(yù)編譯語句對象
Connection對象.prepredStatement(sql);
設(shè)置參數(shù)
使用#{}指定的參數(shù)來作為SQL的參數(shù),#{}取的是指定類型對象的屬性值
執(zhí)行SQL
4.結(jié)果如果是一個結(jié)果集:查詢操作
此時需要將結(jié)果集數(shù)據(jù)封裝成指定類型(使用resultType來指定)的對象
注意:此時要求Java中的對象的屬性的類型(名稱)必須和數(shù)據(jù)庫中列的類型(名稱)的要一致
獲取自動生成的主鍵:
當(dāng)用戶執(zhí)行保存操作之后,立即將保存到數(shù)據(jù)庫中自動生成的主鍵返回回來
在JDBC中可以手動設(shè)置返回自動生成的主鍵:
在MyBatis中如何獲取?
2.在項目中,為自定義的類型設(shè)置別名
在主配置文件中做如下的配置:
3.在項目上線之后,需要管理人員來維護項目,所以,管理人員有可能去修改相關(guān)的配置:如連接數(shù)據(jù)庫的密碼等
為管理人員少犯低級錯誤(將配置文件修改錯),需要將這些需要修改的配置抽取到一個單獨的文件中:db.properties
**4.問題:在執(zhí)行查詢操作(增刪改沒有)的時候,如果屬性名和列名不一致,將造成數(shù)據(jù)封裝失敗的問題
**
解決方案:使用resultMap來對屬性和列做映射
此時,在查詢的SQL中,使用resultMap來指定結(jié)果集的封裝方式
注意:resultType和resultMap不能同時用
使用Mapper接口:
問題:1.在執(zhí)行CRUD操作的時候,需要去獲取到對應(yīng)的SQL語句(通過namespace+sqlid),如果將字符串寫錯,在編譯時期發(fā)現(xiàn)不了...
2.參數(shù)的類型接受的是Object類型的,所以,如果將參數(shù)類型設(shè)置錯了,在編譯時期發(fā)現(xiàn)不了...
解決方案: 使用Mapper接口來解決上面的問題
觀察獲取語句的字符串
com.jd.pss.domain.UserMapper.save
com.jd.pss.domain.UserMapper.delete
com.jd.pss.domain.UserMapper.update
com.jd.pss.domain.UserMapper.get
com.jd.pss.domain.UserMapper.list
上面的字符串很像在指定一個類的全限定名+類中的方法
接口的定義的要求:
public interface UserMapper {
void save(User u);
void delete(Long id);
void update(User u);
User get(Long id);
List<User> list();
}