MyBatis對比Hibernate
Hibernate:全自動映射,雖然方便,但是缺少靈活性,後期還要深入學hql,麻煩。
MyBatis:半自動映射,sql語句寫在配置文件中,由開發人員人員控制。
Mybatis也是輕量級框架
Mybatis實現sql語句定製化,其他流程還是自動化,是結餘Hibernate和JDBC之間的半自動框架。
mybatis的環境搭建
創建一個maven項目
pom文件的常用依賴
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.42</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>
</dependencies>
小注意:
選成自己下載的maven
要打勾的地方
數據庫
實體類(省略了get和set方法)
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
核心配置文件(必須要)
<?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的主配置文件 -->
```java
<configuration>
<!-- 配置properties-->
<properties resource="jdbcConfig.properties"></properties>
<!--配置參數-->
<settings>
<!--開啓Mybatis支持延遲加載-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"></setting>
</settings>
<typeAliases>
<!--typeAlias用於配置別名。type屬性指定的是實體類全限定類名。alias屬性指定別名,當指定了別名就再區分大小寫
<typeAlias type="home.sise.cn.domain.User" alias="user"></typeAlias>-->
<!-- 用於指定要配置別名的包,當指定之後,該包下的實體類都會註冊別名,並且類名就是別名,不再區分大小寫-->
<package name="home.sise.cn.domain"></package>
</typeAliases>
<!-- 配置環境 -->
<environments default="mysql">
<!-- 配置mysql的環境-->
<environment id="mysql">
<!-- 配置事務的類型-->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置數據源(連接池) -->
<dataSource type="POOLED">
<!-- 配置連接數據庫的4個基本信息 -->
<!-- <property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis_day01"/>
<property name="username" value="root"/>
<property name="password" value="3997"/>-->
<property name="driver" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</dataSource>
</environment>
</environments>
<!-- 指定映射配置文件的位置,映射配置文件指的是每個dao獨立的配置文件 -->
<!--<mapper resource="home/sise/cn/dao/IUserDao.xml"></mapper>-->
<!-- package標籤是用於指定dao接口所在的包,當指定了之後就不需要在寫mapper以及resource或者class了 -->
<package name="home.sise.cn.dao"></package>
</configuration>
連接池的屬性有三個
POOLED 使用了連接池(常用)
UNPOOLED 沒有使用連接池,每次請求都會創建一個鏈接
JNDI 需要通過服務器加載,必須是web工程或maven的war工程才能使用
mapper標籤的屬性
resource 用於配置xml方式
class 用於註解方式
package 直接指定dao接口包
typeAlias標籤表示起別名
URI:Uniform Resource Identifier 統一資源標識符。它是在應用中可以唯一定位一個資源的。
URL:Uniform Resource Locator 統一資源定位符。它是可以唯一標識一個資源的位置。
URL用法:
http://localhost:8080/mybatis/ServletTest
協議 主機 端口 URI
在用戶和賬戶的關聯關係中,查詢用戶時,該用戶的賬戶信息應該用的時候再查詢。而查詢賬戶時,該賬戶所屬的用戶信息應該一起查詢出來。
延遲加載:不用的時候不查詢。按需加載
立即加載:只要一調用方法,馬上發起查詢。
一對多,多對多:通常情況下我們都是採用延遲加載。
多對一,一對一:通常情況下我們都是採用立即加載。
配置properties
可以在標籤內部配置連接數據庫的信息。也可以通過屬性引用外部配置文件信息
resource屬性: 常用的
jdbcConfig.properties配置文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis_day01
jdbc.username=root
jdbc.password=3997
mybatis的代理方式(常用)
映射配置文件(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 namespace="home.sise.cn.dao.IUserDao">
<select id="findAll" resultType="home.sise.cn.domain.User">
select * from user
</select>
</mapper>
使用代理方式小注意:
1.mybatis的映射配置文件位置必須和dao接口的包結構相同
2.映射配置文件的mapper標籤的namespace屬性的取值要和dao接口的全限定類名相同
3.映射配置文件的select標籤的id屬性要和dao接口的方法名相同
原因
mybatis在創建工廠加載解析xml配置文件時,是通過把映射配置文件中的namespace+id作爲key,把sq語句和返回類型作爲value放入了map集合中。在我們使用時,通過傳入的接口的全限定名+方法名從放入的map集合中找到對應的信息,然後執行相應的操作。
客戶代碼
public class Mybatis_test {
public static void main(String[] args)throws Exception {
//1.讀取配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.創建SqlSessionFactory工廠
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3.使用工廠生產SqlSession對象
// SqlSession session = factory.openSession();
SqlSession session = factory.openSession(true);
//4.使用SqlSession創建Dao接口的代理對象
IUserDao userDao = session.getMapper(IUserDao.class);
//5.使用代理對象執行方法
List<User> users = userDao.findAll();
for(User user : users){
System.out.println(user);
}
//提交事務
// session.commit();
//6.釋放資源
session.close();
in.close();
}}
使用了建造者模式,工廠方法模式,代理模式
SqlSession session = factory.openSession(true);
表示開啓了自動提交事務
mybatis的接口實現方式
接口實現類
public class UserDaoImpl implements IUserDao {
private SqlSessionFactory factory;
public UserDaoImpl(SqlSessionFactory factory){
this.factory = factory;
}
public List<User> findAll(){
//1.使用工廠創建SqlSession對象
SqlSession session = factory.openSession();
//2.使用session執行查詢所有方法
List<User> users = session.selectList("home.sise.cn.dao.IUserDao.findAll");
session.close();
//3.返回查詢結果
return users;
}
}
客戶代碼
public class MybatisTest {
public static void main(String[] args)throws Exception {
//1.讀取配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.創建SqlSessionFactory工廠
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3.使用工廠創建dao對象
IUserDao userDao = new UserDaoImpl(factory);
//4.使用代理對象執行方法
List<User> users = userDao.findAll();
for(User user : users){
System.out.println(user);
}
//5.釋放資源
in.close();
}
}
mybatis的基本使用
常用增刪改查
映射配置
```java
<?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 namespace="com.itheima.dao.IUserDao">
<!-- 配置 查詢結果的列名和實體類的屬性名的對應關係 -->
<resultMap id="userMap" type="User">
<!-- 主鍵字段的對應 -->
<id property="userId" column="id"></id>
<!--非主鍵字段的對應-->
<result property="userName" column="username"></result>
<result property="userAddress" column="address"></result>
<result property="userSex" column="sex"></result>
<result property="userBirthday" column="birthday"></result>
</resultMap>
<!-- 查詢所有 -->
<select id="findAll" resultMap="userMap">
select * from user;
</select>
<!-- 保存用戶 -->
<insert id="saveUser" parameterType="user">
<!-- 配置插入操作後,獲取插入數據的id -->
<selectKey keyProperty="userId" keyColumn="id" resultType="int" order="AFTER">
select last_insert_id();
</selectKey>
insert into user(username,address,sex,birthday)values(#{userName},#{userAddress},#{userSex},#{userBirthday});
</insert>
<!-- 更新用戶 -->
<update id="updateUser" parameterType="USER">
update user set username=#{userName},address=#{userAddress},sex=#{userAex},birthday=#{userBirthday} where id=#{userId}
</update>
<!-- 刪除用戶-->
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id = #{uid}
</delete>
<!-- 根據id查詢用戶 -->
<select id="findById" parameterType="INT" resultMap="userMap">
select * from user where id = #{uid}
</select>
<!-- 根據名稱模糊查詢 -->
<select id="findByName" parameterType="string" resultMap="userMap">
select * from user where username like #{name}
<!-- select * from user where username like '%${value}%'-->
</select>
<!-- 獲取用戶的總記錄條數 -->
<select id="findTotal" resultType="int">
select count(id) from user;
</select>
<!-- 根據queryVo的條件查詢用戶 -->
<select id="findUserByVo" parameterType="home.sise.cn.domain.QueryVo" resultMap="userMap">
select * from user where username like #{user.username}
</select>
</mapper>
實體類
public class QueryVo {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
小注意:
1.parameterType爲參數類型,resultType爲返回值類型
2.因爲在主配置文件中使用了別名,所以type中可以直接使用user,而且不區分大小寫。
3.parameterType如果爲8中基本類型,那麼佔位符#{}中的值可以任意,如果是其他值,則必須對應着實體類來寫
4.當實體類和數據庫的表沒有一一對應時,可以使用在映射文件中給字段起別名或者resultMap
5.resultMap中,column是數據庫字段,property是實體類屬性,type是返回值類型,id是唯一標識。
mybatis映射文件標籤
if,where標籤
<select id="findUserByCondition" resultMap="userMap" parameterType="user">
select * from user
<where>
<if test="userName != null">
and username = #{userName}
</if>
<if test="userSex != null">
and sex = #{userSex}
</if>
<if test="userAddress !=null">
and address = #{userAddress}
</if>
</where>
</select>
sql,foreach標籤
foreach屬性:
collection:代表要遍歷的集合元素,類似jstl中的items
open:代表語句的開始部分
close:代表結束部分
item:代表遍歷集合的每個元素,類似jstl中的var
sperator:代表分隔符
相當於sql: select * from user where ids != null and ids.size()>0 and id in (?)
<!-- 瞭解的內容:抽取重複的sql語句-->
<sql id="defaultUser">
select * from user
</sql>
<select id="findUserInIds" resultMap="userMap" parameterType="queryvo">
<include refid="defaultUser"></include>
<where>
<if test="ids != null and ids.size()>0">
<foreach collection="ids" open="and id in (" close=")" item="uid" separator=",">
#{uid}
</foreach>
</if>
</where>
</select>
小注意
如果引用其它 mapper.xml 的 sql 片段,則在引用時需要加上 namespace,如下:
<include refid="namespace.sql 片段”/>
mybatis表之間關聯關係
每個賬戶所屬一個用戶 : 一對一
方式一
<!-- 定義封裝account和user的resultMap -->
<resultMap id="accountUserMap" type="account">
<id property="id" column="id"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!-- 一對一的關係映射:配置封裝user的內容
select屬性指定的內容:查詢用戶的唯一標識:
column屬性指定的內容:用戶根據id查詢時,所需要的參數的值
-->
<association property="user" column="uid" javaType="user" select="home.sise.cn.dao.IUserDao.findById"></association>
</resultMap>
<!-- 查詢所有 -->
<select id="findAll" resultMap="accountUserMap">
select * from account
</select>
<!-- 根據用戶id查詢賬戶列表 -->
<select id="findAccountByUid" resultType="account">
select * from account where uid = #{uid}
</select>
方式二
<!-- 定義封裝account和user的resultMap,其中account用到了別名 -->
<resultMap id="accountUserMap" type="account">
<id property="id" column="id"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!-- 一對一的關係映射:配置封裝user的內容-->
<association property="user" column="uid" javaType="user">
<id property="id" column="id"></id>
<result column="username" property="username"></result>
<result column="address" property="address"></result>
<result column="sex" property="sex"></result>
<result column="birthday" property="birthday"></result>
</association>
</resultMap>
<!-- 查詢所有 -->
<select id="findAll" resultMap="accountUserMap">
select u.*,a.id as aid,a.uid,a.money from account a , user u where u.id = a.uid;
</select>
resultMap中id標籤是對應表中的主鍵
一個用戶有多個賬戶 :一對多
<!-- 定義User的resultMap-->
<resultMap id="userAccountMap" type="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<!-- 配置user對象中accounts集合的映射 -->
<collection property="accounts" ofType="account" select="home.sise.cn.dao.IAccountDao.findAccountByUid" column="id"></collection>
</resultMap>
<!-- 查詢所有 -->
<select id="findAll" resultMap="userAccountMap">
select * from user
</select>
<!-- 根據id查詢用戶 -->
<select id="findById" parameterType="INT" resultType="user">
select * from user where id = #{id}
</select>
方式二:
<!-- 定義User的resultMap-->
<resultMap id="userAccountMap" type="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<!-- 配置user對象中accounts集合的映射 -->
<collection property="accounts" ofType="account">
<id column="id" property="id"></id>
<result column="uid" property="uid"></result>
<result column="money" property="money"></result>
</collection>
</resultMap>
<!-- 查詢所有 -->
<select id="findAll" resultMap="userAccountMap">
select * from user u left outer join account a on u.id = a.uid
</select>
mybatis的緩存
緩存是什麼?
存在內存中的臨時數據。
爲什麼使用緩存?
減少和數據庫的交互次數,提高了執行效率。
適合用緩存的情況
1.需要經常進行查詢,而且不會經常變動的。
2.數據的正確與否對最終的結果影響不大。
不適合用緩存的情況
1.經常改變的數據
2.數據的正確與否對最終的影響很大。
例如:商品的庫存,銀行的匯率.
默認一級緩存,範圍是在一個session中
當我們執行查詢之後,查詢的結果會同時存入到session爲我們提供一塊區域中。該區域的結構是一個Map。當我們再次查詢同樣的數據,mybatis會先去session中查詢是否有,有的話直接拿出來用。當session對象消失時,mybatis的一級緩存也就消失了。
當調用 session 的修改,添加,刪除,commit(),close()等方法時,就會清空一級緩存。
二級緩存,範圍是在一個sessionFactory中
二級緩存存放的是數據
使用步驟:
第一步:讓Mybatis框架支持二級緩存(在SqlMapConfig.xml中配置)
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
第二步:讓當前的映射文件支持二級緩存(在IUserDao.xml中配置)
第三步:讓當前的操作支持二級緩存(在select標籤中配置)
<mapper namespace="home.sise.cn.dao.IUserDao">
<!--開啓user支持二級緩存-->
<cache/>
<!-- 根據id查詢用戶 -->
<select id="findById" parameterType="INT" resultType="user" useCache="true">
select * from user where id = #{uid}
</select>
</mapper>