一,Mybatis入門和自定義Mybatis
1.架構概述
1)什麼是架構
它是我們軟體開發中的一套解決方案,不同的架構解決的是不同的問題。
使用架構的好處:
架構封裝了很多的細節,使開發者可以使用極簡的方式實作功能。大大提高開發效率。
2)三層架構
-
表現層:
是用于展示資料的
-
業務層:
是處理業務需求
-
持久層:
是和資料庫互動的
3)持久層技術解決方案
-
JDBC技術:
Connection
PreparedStatement
ResultSet
-
Spring的JdbcTemplate:
Spring中對jdbc的簡單封裝
-
Apache的DBUtils:
它和Spring的JdbcTemplate很像,也是對Jdbc的簡單封裝
以上這些都不是架構
JDBC是規範
Spring的JdbcTemplate和Apache的DBUtils都隻是工具類
4)Mybatis概述
mybatis是一個持久層架構,用java編寫的。
它封裝了jdbc操作的很多細節,使開發者隻需要關注sql語句本身,而無需關注注冊驅動,建立連接配接等繁雜過程它使用了ORM思想實作了結果集的封裝。
ORM:
Object Relational Mappging 對象關系映射
簡單的說:
就是把資料庫表和實體類及實體類的屬性對應起來
讓我們可以操作實體類就實作操作資料庫表。
user User
id userId
user_name userName
我們需要做到
實體類中的屬性和資料庫表的字段名稱保持一緻。
user User
id id
user_name user_name
`
2.Mybatis入門
1)mybatis的環境搭建
建立測試資料庫;
第一步:建立maven工程并導入坐标
第二步:建立實體類和dao的接口
第三步:建立Mybatis的主配置檔案
SqlMapConifg.xml
導入log4j的配置檔案
第四步:建立映射配置檔案
IUserDao.xml
第五步:編寫測試類
2)環境搭建的注意事項
第一個:建立IUserDao.xml 和 IUserDao.java時名稱是為了和我們之前的知識保持一緻。
在Mybatis中它把持久層的操作接口名稱和映射檔案也叫做:Mapper
是以:IUserDao 和 IUserMapper是一樣的
第二個:在idea中建立目錄的時候,它和包是不一樣的
包在建立時:com.itheima.dao它是三級結構
目錄在建立時:com.itheima.dao是一級目錄
第三個:mybatis的映射配置檔案位置必須和dao接口的包結構相同
第四個:映射配置檔案的mapper标簽namespace屬性的取值必須是dao接口的全限定類名
第五個:映射配置檔案的操作配置(select),id屬性的取值必須是dao接口的方法名
當我們遵從了第三,四,五點之後,我們在開發中就無須再寫dao的實作類。
3)mybatis的入門案例
第一步:讀取配置檔案
第二步:建立SqlSessionFactory工廠
第三步:建立SqlSession
第四步:建立Dao接口的代理對象
第五步:執行dao中的方法
第六步:釋放資源
注意事項:
不要忘記在映射配置中告知mybatis要封裝到哪個實體類中
配置的方式:指定實體類的全限定類名
4)基于xml形式的配置
pom.xml
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
User
public class User {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
'}';
}
}
UserDao
public interface UserDao {
List<User> findAll();
}
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>
<!-- 配置 mybatis 的環境 -->
<environments default="mysql">
<!-- 配置 mysql 的環境 -->
<environment id="mysql">
<!-- 配置事務的類型 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置連接配接資料庫的資訊:用的是資料源(連接配接池) -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/eesy"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- 告知 mybatis 映射配置的位置 -->
<mappers>
<mapper resource="com/atguigu/dao/UserDao.xml"/>
</mappers>
</configuration>
userDao.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="com.atguigu.dao.UserDao">
<select id="findAll" resultType="com.atguigu.domain.User">
select * from user;
</select>
</mapper>
測試類
public class Test1 {
@Test
public void test1()throws Exception{
//1.加載配置檔案
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
//2.創造建構者對象
SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
//3.建構者構件工廠
SqlSessionFactory factory = builder.build(is);
//4.使用工廠生産sqlSession
SqlSession session = factory.openSession();
//5.使用sqlSession建立userDao的代理對象
UserDao dao = session.getMapper(UserDao.class);
List<User> users = dao.findAll();
for (User user:users){
System.out.println(user);
}
//6.資源關閉
session.close();
is.close();
}
}
5)基于注解形式配置
mybatis基于注解的入門案例:
把IUserDao.xml移除,在dao接口的方法上使用@Select注解,并且指定SQL語句
同時需要在SqlMapConfig.xml中的mapper配置時,使用class屬性指定dao接口的全限定類名。
Dao層
@select("select * from user")
public interface UserDao {
List<User> findAll();
}
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>
<!-- 配置 mybatis 的環境 -->
<environments default="mysql">
<!-- 配置 mysql 的環境 -->
<environment id="mysql">
<!-- 配置事務的類型 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置連接配接資料庫的資訊:用的是資料源(連接配接池) -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/eesy"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- 告知 mybatis 映射配置的位置 -->
<mappers>
<mapper resource="com.atguigu.dao.UserDao"/>
</mappers>
</configuration>
6)帶有實作類的dao
明确:
我們在實際開發中,都是越簡便越好,是以都是采用不寫dao實作類的方式。
不管使用XML還是注解配置。
但是Mybatis它是支援寫dao實作類的。
UserDaoImpl
/**
* @author Guohai
* @createTime 2020-07-14 20:40
*/
public class UserDaoImpl implements UserDao {
private SqlSessionFactory factory;
public UserDaoImpl(SqlSessionFactory factory) {
this.factory = factory;
}
public List<User> findAll() {
SqlSession session = factory.openSession();
List<User> list = session.selectList("com.atguigu.dao.impl.UserDaoImpl");
session.close();
return list;
}
}
測試類
public void test1()throws Exception{
//1.加載配置檔案
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
//2.創造建構者對象
SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
//3.建構者構件工廠
/**
* 建立工廠,Mybatis使用了建構者模式,
* 把對象的建立細節隐藏,使使用者直接調用方法
* 就可以拿到對象。
*/
SqlSessionFactory factory = builder.build(is);
//4.使用工廠生産sqlSession
/**
* 使用工廠模式生産SQLSession對象,
* 優勢:解耦,降低了類之間的依賴關系
*/
SqlSession session = factory.openSession();
//5.使用sqlSession建立userDao的代理對象
/**
* 建立dao接口實作類使用了代理模式,
* 在不改變源碼的基礎上對方法進行增強。
*/
UserDao dao = session.getMapper(UserDao.class);
List<User> users = dao.findAll();
for (User user:users){
System.out.println(user);
}
//6.資源關閉
session.close();
is.close();
}
關于配置檔案加載的詳解
讀取配置檔案,用到的就是解析xml的技術,
此處用到dom4j解析xml技術。
mybatis-config.xml
1.提供資料源(提供連接配接對象)
2.指定映射配置資訊(指定xxxDao.xml)
xxxDao.xml
1.查詢語句
2.封裝結果集對象的全限定類名
namespace:xxxDao
-将查詢語句和封裝結果集對象的全限定類名
封裝在一個map集合中,友善查詢,
key為dao接口名.方法名,
value為:查詢語句和封裝結果集對象的全限定類名。
建立代理對象分析
public static void main(String[] args) {
UserDao userDao;
/**
* @param 1.被代理類的類加載器
* @param 2.被代理類實作的接口
* @param 3.對方法的增強:listAll()就是在此處被調用的。
*/
UserDao daoimpl = (UserDao) Proxy.newProxyInstance(
UserDao.class.getClassLoader(),
UserDao.class.getInterfaces(),
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;//在此處調用查詢所有的方法
}
});
}
7)Mybatis的執行流程

3.自定義Mybatis分析
建構一個屬于自己的持久層架構,将會涉及到的一些知識點:工廠模式
(Factory 工廠模式、構造者模式(Builder 模式、代理模式,反射,自定義注解,注解的反射,xml 解析,
資料庫中繼資料,中繼資料的反射等)
1.用一個流來加載配置檔案
解析xml檔案
2.用一個類來建立工廠類
建構者模式,隐藏建立細節
3.用工廠類來造sqlSession對象
工廠模式造對象,解耦
4.使用SQLSession動态代理建立dao的接口實作類對象
不改變源碼的基礎上,對原有方法進行增強。
二,基于代理Dao實作CRUD
1.環境搭建
第一步:建立 maven 工程
第二步:導入坐标
第三步:編寫必要代碼(實體類和持久層接口)
第四步:編寫 mybatis-config.xml
第五步:編寫映射配置檔案
第六步:編寫測試類
2.使用要求
1、持久層接口和持久層接口的映射配置必須在相同的包下。
2、持久層映射配置中 mapper 标簽的 namespace 屬性取值必須是持久層接口的全限定類名。
3、SQL 語句的配置标簽,,,的 id 屬性必須和持久層接口的方法名相同。
3.實作功能
1.測試查詢所有的方法
2.添加方法
3.删除
4.更新
5.根據id查詢
6.模糊查詢
7.使用聚合函數查詢:查詢表中有多少條記錄數
8.parameterType傳遞pojo類型參數:根據名字查詢
代碼實作
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>
<!-- 配置 mybatis 的環境 -->
<environments default="mysql">
<!-- 配置 mysql 的環境 -->
<environment id="mysql">
<!-- 配置事務的類型 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置連接配接資料庫的資訊:用的是資料源(連接配接池) -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/eesy"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- 告知 mybatis 映射配置的位置 -->
<mappers>
<mapper resource="com/atguigu/dao/UserDao.xml"/>
</mappers>
</configuration>
UserDao.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="com.atguigu.dao.UserDao">
<!--自定義封裝結果集-->
<!-- 建立 User 實體和資料庫表的對應關系
type 屬性:指定實體類的全限定類名
id 屬性:給定一個唯一辨別,是給查詢 select 标簽引用用的。
-->
<resultMap id="map" type="com.atguigu.domain.User">
<!--配置主鍵-->
<id column="id" property="id"></id>
<!--配置其他列-->
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
<result column="username" property="username"></result>
<!--
id 标簽:用于指定主鍵字段
result 标簽:用于指定非主鍵字段
column 屬性:用于指定資料庫列名
property 屬性:用于指定實體類屬性名稱
-->
</resultMap>
<!--查詢所有-->
<select id="findAll" resultType="com.atguigu.domain.User">
select * from user;
</select>
<!--添加方法-->
<insert id="saveUser" parameterType="com.atguigu.domain.User">
<!-- 配置儲存時擷取插入的 id -->
<selectKey keyColumn="id" keyProperty="id" resultType="int" order="AFTER">
select last_insert_id();
</selectKey>
insert into user(username, birthday, sex, address)
values (#{username}, #{birthday}, #{sex}, #{address});
</insert>
<!--删除-->
<delete id="deleteUser" parameterType="java.lang.Integer">
<!--
#{id}:作為占位符,名字可以随便起。
parameterType:隻要能表示出是int就可以
-->
delete from user where id = #{id};
</delete>
<!--更新-->
<update id="updateUser" parameterType="com.atguigu.domain.User">
update user
set username=#{username},
birthday=#{birthday},
sex=#{sex},
address=#{address}
where id = #{id};
</update>
<!--根據id查詢-->
<select id="findById" parameterType="int" resultType="com.atguigu.domain.User">
select * from user where id = #{id};
</select>
<!--模糊查詢-->
<select id="findLike" resultType="com.atguigu.domain.User" parameterType="String">
<!--此種寫法,需要在調用方法傳遞的參數兩邊加%-->
<!-- select * from user where username like #{name};-->
<!--
我們在上面将原來的#{}占位符,改成了${value}。
注意如果用模糊查詢的這種寫法,那麼${value}的寫法就是固定的,不能寫成其它名字。
-->
select * from user where username like '%${value}%';
</select>
<!--聚合函數-->
<select id="count" resultType="java.lang.Integer">
select count(*) from user;
</select>
<!--parameterType傳遞pojo類型參數,根據名字查詢-->
<select id="find2" resultType="com.atguigu.domain.User"
parameterType="com.atguigu.domain.MyQuery">
select * from user where username like #{user.username};
</select>
</mapper>
UserDao
public interface UserDao {
/**
* 查詢所有
*/
List<User> findAll();
/**
* 添加
*/
void saveUser(User user);
/**
* 删除
*/
void deleteUser(Integer id);
/**
* 更新
*/
void updateUser(User user);
/**
* 根據id查詢
*/
User findById(Integer id);
/**
* 模糊查詢
*/
List<User> findLike(String name);
/**
* 使用聚合函數查詢
* 查詢表中有多少條記錄數
*/
Integer count();
/**
* parameterType傳遞pojo類型參數
* 根據名字查詢
*/
List<User> find2(MyQuery query);
}
測試類
public class Test1 {
private InputStream is;
private SqlSession session;
private UserDao userDao;
@Before
public void init() throws Exception {
is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
session = factory.openSession();
userDao = session.getMapper(UserDao.class);
}
@After
public void destory()throws Exception{
session.commit();//預設自動送出為false
session.close();
is.close();
}
/**
* 測試查詢所有的方法
*/
@Test
public void test1(){
List<User> users = userDao.findAll();
for (User user:users){
System.out.println(user);
}
}
/**
* 添加方法
*/
@Test
public void test2(){
User user = new User();
user.setUsername("張三");
user.setSex("男");
user.setAddress("黑龍江");
user.setBirthday(new Date());
userDao.saveUser(user);
//儲存後傳回使用者id
System.out.println(user.getId());
}
/**
* 删除
*/
@Test
public void test3(){
userDao.deleteUser(41);
}
/**
* 更新
*/
@Test
public void test4(){
User user = new User();
user.setUsername("李四");
user.setSex("男");
user.setAddress("黑龍江");
user.setBirthday(new Date());
user.setId(49);
userDao.updateUser(user);
}
/**
* 根據id查詢
*/
@Test
public void test5(){
User user = userDao.findById(49);
System.out.println(user);
}
/**
* 模糊查詢1
* 第一種配置方式#{username}
*/
@Test
public void test6(){
List<User> users = userDao.findLike("%王%");
for (User user :users){
System.out.println(user);
}
}
/**
* 模糊查詢2
* 第二種配置方式:${value}固定寫法
*/
@Test
public void test7(){
List<User> users = userDao.findLike("王");
for (User user :users){
System.out.println(user);
}
}
/**
* 使用聚合函數查詢
* 查詢表中有多少條記錄數
*/
@Test
public void test8(){
Integer count = userDao.count();
System.out.println(count);
}
/**
* parameterType傳遞pojo類型參數
* 根據名字查詢
*/
@Test
public void test9(){
MyQuery myQuery = new MyQuery();
User user = new User();
user.setUsername("%王%");
myQuery.setUser(user);
List<User> users = userDao.find2(myQuery);
for (User u :users){
System.out.println(u);
}
}
}
4.Mybatis-config.xml
1)全局配置檔案結構
configuration 配置
-properties(屬性)
--property
-settings(全局配置參數)
--setting
-typeAliases(類型别名)
--typeAliase
--package
-typeHandlers(類型處理器)
-objectFactory(對象工廠)
-plugins(插件)
-environments(環境集合屬性對象)
--environment(環境子屬性對象)
---transactionManager(事務管理)
---dataSource(資料源)
-databaseIdProvider (資料庫廠商辨別)
-mappers(映射器)
--mapper
--package
2)properties(屬性)
在使用 properties 标簽配置時,我們可以采用兩種方式指定屬性配置。
①第一種,配置放在本配置檔案内
<properties>
<property name="jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="jdbc.url" value="jdbc:mysql://localhost:3306/eesy"/>
<property name="jdbc.username" value="root"/>
<property name="jdbc.password" value="root"/>
</properties>
②第二種,配置放在單獨的配置檔案
在 classpath 下定義 db.properties檔案
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/eesy
jdbc.username=root
jdbc.password=123456
properties标簽配置
<!-- 配置連接配接資料庫的資訊
resource 屬性:用于指定 properties 配置檔案的位置,要求配置檔案必須在類路徑下
resource="jdbcConfig.properties"
url 屬性:
URL: Uniform Resource Locator 統一資源定位符
http://localhost:8080/mystroe/CategoryServlet URL
協定 主機 端口 URI
URI:Uniform Resource Identifier 統一資源辨別符
/mystroe/CategoryServlet
它是可以在 web 應用中唯一定位一個資源的路徑
-->
<properties resource="db.properties"></properties>
此時dataSource 标簽就變成了引用上面的配置(動态設定)
<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>
3)settings(設定)
這是 MyBatis 中極為重要的調整設定,它們會改變 MyBatis 的運作時行為。
包含如下的 setting 設定:
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="useGeneratedKeys" value="false"/>
<setting name="autoMappingBehavior" value="PARTIAL"/>
<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25"/>
<setting name="defaultFetchSize" value="100"/>
<setting name="safeRowBoundsEnabled"value="false"/>
<setting name="mapUnderscoreToCamelCase" value="false"/>
<setting name="localCacheScope" value="SESSION"/>
<setting name="jdbcTypeForNull" value="OTHER"/>
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>
4)typeAliases(類型别名)
在前面我們講的 Mybatis 支援的預設别名,我們也可以采用自定義别名方式來開發。
第一種,類型别名是為 Java 類型設定一個短的名字,可以友善我們引用某個類。
<typeAliases>
<typeAlias alias="user" type="com.atguigu.domain.User"/>
</typeAliases>
第二種,類很多的情況下,可以批量設定别名這個包下的每一個類建立一個預設的别名,就是簡單類名小寫。
<typeAliases>
<package name="com.atguigu.domain.beans"/>
</typeAliases>
5)typeHandlers(類型處理器)
- 無論是 MyBatis 在預處理語句(PreparedStatement)中設定一個參數時,還是從結果集中取出一個值時, 都會用類型處理器将擷取的值以合适的方式轉換成 Java 類型。
- 日期和時間的處理,JDK1.8 以前一直是個頭疼的問題。我們通常使用 JSR310 規範上司者 Stephen Colebourne 建立的 Joda-Time 來操作。1.8 已經實作全部的 JSR310 規範了
- 日期時間處理上,我們可以使用 MyBatis 基于 JSR310(Date and Time API)編寫的各種日期時間類型處理器。
- MyBatis3.4 以前的版本需要我們手動注冊這些處理器,以後的版本都是自動注冊的,如需注冊,需要下載下傳 mybatistypehandlers-jsr310,并通過如下方式注冊。
自定義類型轉換器
①我們可以重寫類型處理器或建立自己的類型處理器來處理不支援的或非标準的類型。
②步驟:
實作 org.apache.ibatis.type.TypeHandler 接口或者繼承org.apache.ibatis.type.BaseTypeHandler
指定其映射某個 JDBC 類型(可選操作)
在mybatis全局配置檔案中注冊
6)environments 環境配置
environments标簽中的default屬性指定一個環境的辨別符來快速的切換環境。
每種環境使用一個 environment 标簽進行配置并指定唯一辨別符。
<!--
environment-指定具體環境
id:指定目前環境的唯一辨別,transactionManager、和 dataSource 都必須有。
* transactionManager:
type: JDBC | MANAGED | 自定義
JDBC:使用了 JDBC 的送出和復原設定,依賴于從資料源得到的連接配接來管理事務範圍JdbcTransactionFactory
MANAGED:不送出或復原一個連接配接、讓容器來管理事務的整個生命周期(比如 JEE應用伺服器的上下文)。 ManagedTransactionFactory
自定義:實作 TransactionFactory 接口,type=全類名/别名
* dataSource
type: UNPOOLED | POOLED | JNDI | 自定義
UNPOOLED:不使用連接配接池, UnpooledDataSourceFactory
POOLED:使用連接配接池, PooledDataSourceFactory
JNDI: 在 EJB 或應用伺服器這類容器中查找指定的資料源
自定義:實作 DataSourceFactory 接口,定義資料源的擷取方式。
實際開發中我們使用 Spring 管理資料源,并進行事務控制的配置來覆寫上述配置。
-->
<environments default="oracle">
<environment id="mysql">
<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>
7)mappers(映射器)
作用:用來在 mybatis 初始化的時候,告訴 mybatis 需要引入哪些 Mapper 映射檔案。
mapper 屬性:
- resource : 引入類路徑下的檔案
- url : 引入網絡路徑或者是磁盤路徑下的檔案
-
class : 引入 Mapper 接口
有 SQL 映射檔案 , 要求 Mapper 接口與 SQL 映射檔案同名同。
沒有 SQL 映射檔案 , 使用注解在接口的方法上寫 SQL 語句。
使用相對于類路徑的資源
如:<mapper resource="com/itheima/dao/IUserDao.xml" />
使用 mapper 接口類路徑
如:<mapper class="com.itheima.dao.UserDao"/>
注意:此種方法要求 mapper 接口名稱和 mapper 映射檔案名稱相同,且放在同一個目錄中。
注冊指定包下的所有 mapper 接口
如:<package name="cn.itcast.mybatis.mapper"/>
注意:此種方法要求 mapper 接口名稱和 mapper 映射檔案名稱相同,且放在同一個目錄中。
5.XxxDao.xml映射檔案
1)select 标簽
resultType 屬性:
用于指定結果集的類型。
parameterType 屬性:
用于指定傳入參數的類型。
sql 語句中使用#{}字元: 它代表占位符,相當于原來 jdbc 部分所學的?,都是用于執行語句時替換實際的資料。
具體的資料是由#{}裡面的内容決定的。
#{}中内容的寫法:
由于資料類型是基本類型,是以此處可以随意寫。
例如:
<select id="getEmployeeById"
resultType="com.atguigu.mybatis.beans.Employee"
databaseId="mysql">
select * from tbl_employee where id = ${_parameter}
</select>
2)insert标簽
parameterType 屬性:
代表參數的類型,因為我們要傳入的是一個類的對象,是以類型就寫類的全名稱。
sql 語句中使用#{}字元: 它代表占位符,相當于原來 jdbc 部分所學的?,都是用于執行語句時替換實際的資料。
具體的資料是由#{}裡面的内容決定的。
#{}中内容的寫法:
由于我們儲存方法的參數是 一個 User 對象,此處要寫 User 對象中的屬性名稱。
它用的是 ognl 表達式。
例如:
<insert id="insertEmployee"
parameterType="com.atguigu.mybatis.beans.Employee"
databaseId="mysql">
insert into tbl_employee(last_name,email,gender)
values(#{lastName},#{email},#{gender})
</insert>
3)OGNL表達式
ognl 表達式:
它是 apache 提供的一種表達式語言,全稱是:Object Graphic Navigation Language 對象圖導航語言,它是按照一定的文法格式來擷取資料的。
文法格式:
使用 #{對象.對象}的方式。
說明:
#{user.username}它會先去找 user 對象,然後在 user 對象中找到 username 屬性,并調用
getUsername()方法把值取出來。但是我們在 parameterType 屬性上指定了實體類名稱,是以可以省略 user.
而直接寫 username。
4)主鍵生成方式、擷取主鍵值
①主鍵生成方式
- 支援主鍵自增,例如 MySQL 資料庫
- 不支援主鍵自增,例如 Oracle 資料庫
②擷取主鍵值
若資料庫支援自動生成主鍵的字段(比如 MySQL 和 SQL Server),則可以設定useGeneratedKeys=“true”,然後再把keyProperty設定到目标屬性上。
<insert id="insertEmployee"parameterType="com.atguigu.beans.Employee"
databaseId="mysql"
useGeneratedKeys="true"
keyProperty="id">
insert into tbl_employee(last_name,email,gender)
values(#{lastName},#{email},#{gender})
</insert>
而對于不支援自增型主鍵的資料庫(例如 Oracle),則可以使用 selectKey 子元素:selectKey 元素将會首先運作,id 會被設定,然後插入語句會被調用。
<insert id="insertEmployee" parameterType="com.atguigu.beans.Employee" databaseId="Oracle">
<selectKey order="BEFORE" keyProperty="id" resultType="integer">
select employee_seq.nextval from dual
</selectKey>
insert into orcl_employee(id,last_name,email,gender)
value(#{id},#{lastName},#{email},#{gender})
</insert>
4)新增使用者id的傳回
新增使用者後,同時還要傳回目前新增使用者的 id 值,因為 id 是由資料庫的自動增長來實作的,是以就相
當于我們要在新增後将自動增長 auto_increment 的值傳回。
<insert id="saveUser" parameterType="USER">
<!-- 配置儲存時擷取插入的 id -->
<selectKey keyColumn="id" keyProperty="id" resultType="int">
select last_insert_id();
</selectKey>
insert into user(username,birthday,sex,address)
values(#{username},#{birthday},#{sex},#{address})
</insert>
5)根據名稱模糊查詢
①第一種方式
我們在配置檔案中沒有加入%來作為模糊查詢的條件,是以在傳入字元串實參時,就需要給定模糊查詢的辨別%。配置檔案中的#{username}也隻是一個占位符,是以 SQL 語句顯示為“ ?”。
<!-- 根據名稱模糊查詢 -->
<select id="findByName" resultType="com.itheima.domain.User" parameterType="String">
select * from user where username like #{username}
</select>
@Test
public void testFindByName(){
//5.執行查詢一個方法
List<User> users = userDao.findByName("%王%");
for(User user : users){
System.out.println(user);
}
}
②第二種方式
<!-- 根據名稱模糊查詢 -->
<select id="findByName" parameterType="string" resultType="com.itheima.domain.User">
select * from user where username like '%${value}%'
</select>
我們在上面将原來的#{}占位符,改成了${value}。注意如果用模糊查詢的這種寫法,那麼${value}的寫法就是固定的,不能寫成其它名字。
/**
* 測試模糊查詢操作
*/
@Test
public void testFindByName(){
//5.執行查詢一個方法
List<User> users = userDao.findByName("王");
for(User user : users){
System.out.println(user);
}
}
6)#{}和${}的差別
#{}表示一個占位符号
通過#{}可以實作 preparedStatement 向占位符中設定值,自動進行 java 類型和 jdbc 類型轉換,#{}可以有效防止 sql 注入。 #{}可以接收簡單類型值或 pojo 屬性值。 如果 parameterType 傳輸單個簡單類型值,#{}括号中可以是 value 或其它名稱。
${}表示拼接sql串
通過${}可以将 parameterType 傳入的内容拼接在 sql 中且不進行 jdbc 類型轉換, ${}可以接收簡單類型值或 pojo 屬性值,如果 parameterType 傳輸單個簡單類型值,${}括号中隻能是 value。${} 有 SQL 注入問題。
7)模糊查詢${value}的源碼
@Override
public String handleToken(String content) {
Object parameter = context.getBindings().get("_parameter");
if (parameter == null) {
context.getBindings().put("value", null);
} else if (SimpleTypeRegistry.isSimpleType(parameter.getClass())) {
context.getBindings().put("value", parameter);
}
Object value = OgnlCache.getValue(content, context.getBindings());
String srtValue = (value == null ? "" : String.valueOf(value));
checkInjection(srtValue);
return srtValue;
}
這就說明了源碼中指定了讀取的 key 的名字就是”value”,是以我們在綁定參數時就隻能叫 value 的名字了。
8)parameterType 傳遞實體類的包裝類
開發中通過 pojo 傳遞查詢條件 ,查詢條件是綜合的查詢條件,不僅包括使用者查詢條件還包括其它的查詢條件(比如将使用者購買商品資訊也作為查詢條件),這時可以使用包裝對象傳遞輸入參數。
Pojo 類中包含 pojo。
需求:根據使用者名查詢使用者資訊,查詢條件放到 QueryVo 的 user 屬性中。
MyQuery類
public class MyQuery {
private User user;
private Integer password;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Integer getPassword() {
return password;
}
public void setPassword(Integer password) {
this.password = password;
}
}
配置檔案
<!--parameterType傳遞pojo類型參數,根據名字查詢-->
<select id="find2" resultType="com.atguigu.domain.User"
parameterType="com.atguigu.domain.MyQuery">
select * from user where username like #{user.username};
</select>
測試類
/**
* parameterType傳遞pojo類型參數
* 根據名字查詢
*/
@Test
public void test9(){
MyQuery myQuery = new MyQuery();
User user = new User();
user.setUsername("%王%");
myQuery.setUser(user);
List<User> users = userDao.find2(myQuery);
for (User u :users){
System.out.println(u);
}
}
9)resultType 配置結果類型
封裝結果集
resultType配置結果類型
當他為實體類全限定類名,必須讓實體類的屬性名與資料庫表的列名對應,否則,資料會封裝不進去,當然,也存在解決辦法。
解決辦法:
1.起别名,在sql語句中給資料庫表的列名起别名,别名與實體類的屬性名一緻。
優點:執行效率高
缺點:開發效率低
2.配置resultMap,自定義一個resultMap,在select标簽中進行引用。
優點:開發效率高
缺點:執行效率低
<resultMap id="userMap" type="com.atguigu.domain.User">
<!--配置主鍵-->
<id column="id" property="id"></id>
<!--配置其他列-->
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
<result column="username" property="username"></result>
<!--
id 标簽:用于指定主鍵字段
result 标簽:用于指定非主鍵字段
column 屬性:用于指定資料庫列名
property 屬性:用于指定實體類屬性名稱
-->
</resultMap>
<!-- 配置查詢所有操作 -->
<select id="findAll" resultMap="userMap">
select * from user
</select>
6.Mybatis與jdbc程式設計比較
1.資料庫連結建立、釋放頻繁造成系統資源浪費進而影響系統性能,如果使用資料庫連結池可解決此問題。
解決:在 SqlMapConfig.xml 中配置資料連結池,使用連接配接池管理資料庫連結。
2.Sql 語句寫在代碼中造成代碼不易維護,實際應用 sql 變化的可能較大,sql 變動需要改變 java 代碼。
解決:将 Sql 語句配置在 XXXXmapper.xml 檔案中與 java 代碼分離。
3.向 sql 語句傳參數麻煩,因為 sql 語句的 where 條件不一定,可能多也可能少,占位符需要和參數對應。
解決:Mybatis 自動将 java 對象映射至 sql 語句,通過 statement 中的 parameterType 定義輸入參數的類型。
4.對結果集解析麻煩,sql 變化導緻解析代碼變化,且解析前需要周遊,如果能将資料庫記錄封裝成 pojo 對象解析比較友善。
解決:Mybatis 自動将 sql 執行結果映射至 java 對象,通過 statement 中的 resultType 定義輸出結果的類型
三, Mybatis 傳統 DAO 層開發[了解]
Dao接口
public interface UserDao {
/**
* 查詢所有
*/
List<User> findAll();
/**
* 添加
*/
void saveUser(User user);
/**
* 删除
*/
void deleteUser(Integer id);
/**
* 更新
*/
void updateUser(User user);
/**
* 根據id查詢
*/
User findById(Integer id);
/**
* 模糊查詢
*/
List<User> findLike(String name);
/**
* 使用聚合函數查詢
* 查詢表中有多少條記錄數
*/
Integer count();
}
Dao接口實作類
public class UserDaoImpl implements UserDao {
private SqlSessionFactory factory;
public UserDaoImpl(SqlSessionFactory factory) {
this.factory = factory;
}
public List<User> findAll() {
SqlSession session = factory.openSession();
List<User> users = session.selectList("com.atguigu.dao.UserDao.findAll");
session.close();
return users;
}
public void saveUser(User user) {
SqlSession session = factory.openSession();
session.insert("com.atguigu.dao.UserDao.saveUser",user);
session.commit();
session.close();
}
public void deleteUser(Integer id) {
SqlSession session = factory.openSession();
session.delete("com.atguigu.dao.UserDao.deleteUser",id);
session.commit();
session.close();
}
public void updateUser(User user) {
SqlSession session = factory.openSession();
session.update("com.atguigu.dao.UserDao.updateUser",user);
session.commit();
session.close();
}
public User findById(Integer id) {
SqlSession session = factory.openSession();
User user = session.selectOne("com.atguigu.dao.UserDao.findById", id);
session.commit();
session.close();
return user;
}
public List<User> findLike(String name) {
SqlSession session = factory.openSession();
List<User> users = session.selectList("com.atguigu.dao.UserDao.findAll",name);
session.close();
return users;
}
public Integer count() {
SqlSession session = factory.openSession();
Integer o = session.selectOne("com.atguigu.dao.UserDao.count");
session.commit();
session.close();
return o;
}
}
配置檔案
<?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.atguigu.dao.UserDao">
<!--自定義封裝結果集-->
<!-- 建立 User 實體和資料庫表的對應關系
type 屬性:指定實體類的全限定類名
id 屬性:給定一個唯一辨別,是給查詢 select 标簽引用用的。
-->
<resultMap id="map" type="com.atguigu.domain.User">
<!--配置主鍵-->
<id column="id" property="id"></id>
<!--配置其他列-->
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
<result column="username" property="username"></result>
<!--
id 标簽:用于指定主鍵字段
result 标簽:用于指定非主鍵字段
column 屬性:用于指定資料庫列名
property 屬性:用于指定實體類屬性名稱
-->
</resultMap>
<!--查詢所有-->
<select id="findAll" resultType="com.atguigu.domain.User">
select *
from user;
</select>
<!--添加方法-->
<insert id="saveUser" parameterType="com.atguigu.domain.User">
<!-- 配置儲存時擷取插入的 id -->
<selectKey keyColumn="id" keyProperty="id" resultType="int" order="AFTER">
select last_insert_id();
</selectKey>
insert into user(username, birthday, sex, address)
values (#{username}, #{birthday}, #{sex}, #{address});
</insert>
<!--删除-->
<!--
#{id}:作為占位符,名字可以随便起。
parameterType:隻要能表示出是int就可以
-->
<delete id="deleteUser" parameterType="java.lang.Integer">
delete
from user
where id = #{id};
</delete>
<!--更新-->
<update id="updateUser" parameterType="com.atguigu.domain.User">
update user
set username=#{username},
birthday=#{birthday},
sex=#{sex},
address=#{address}
where id = #{id};
</update>
<!--根據id查詢-->
<select id="findById" parameterType="int" resultType="com.atguigu.domain.User">
select *
from user
where id = #{id};
</select>
<!--模糊查詢-->
<select id="findLike" resultType="com.atguigu.domain.User" parameterType="String">
<!--此種寫法,需要在調用方法傳遞的參數兩邊加%-->
<!-- select * from user where username like #{name};-->
<!--
我們在上面将原來的#{}占位符,改成了${value}。
注意如果用模糊查詢的這種寫法,那麼${value}的寫
法就是固定的,不能寫成其它名字。
-->
select * from user where username like '%${value}%';
</select>
<!--聚合函數-->
<select id="count" resultType="java.lang.Integer">
select count(*)
from user;
</select>
<!--parameterType傳遞pojo類型參數,根據名字查詢-->
<select id="find2" resultType="com.atguigu.domain.User"
parameterType="com.atguigu.domain.MyQuery">
select *
from user
where username like #{user.username};
</select>
</mapper>
測試類
public class Test1 {
private InputStream is;
private UserDao userDao;
@Before
public void init()throws Exception {
is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
userDao=new UserDaoImpl(factory);
}
@After
public void destory()throws Exception{
is.close();
}
/**
* 測試查詢所有的方法
*/
@Test
public void test1(){
List<User> users = userDao.findAll();
for (User user:users){
System.out.println(user);
}
}
/**
* 添加方法
*/
@Test
public void test2(){
User user = new User();
user.setUsername("張三");
user.setSex("男");
user.setAddress("黑龍江");
user.setBirthday(new Date());
userDao.saveUser(user);
//儲存後傳回使用者id
System.out.println(user.getId());
}
/**
* 删除
*/
@Test
public void test3(){
userDao.deleteUser(41);
}
/**
* 更新
*/
@Test
public void test4(){
User user = new User();
user.setUsername("李四");
user.setSex("男");
user.setAddress("黑龍江");
user.setBirthday(new Date());
user.setId(49);
userDao.updateUser(user);
}
/**
* 根據id查詢
*/
@Test
public void test5(){
User user = userDao.findById(49);
System.out.println(user);
}
/**
* 模糊查詢1
* 第一種配置方式#{username}
*/
@Test
public void test6(){
List<User> users = userDao.findLike("%王%");
for (User user :users){
System.out.println(user);
}
}
/**
* 模糊查詢2
* 第二種配置方式:${value}固定寫法
*/
@Test
public void test7(){
List<User> users = userDao.findLike("王");
for (User user :users){
System.out.println(user);
}
}
/**
* 使用聚合函數查詢
* 查詢表中有多少條記錄數
*/
@Test
public void test8(){
Integer count = userDao.count();
System.out.println(count);
}
}
Mybatis後續的學習:
mybatis 事務 | 動态SQL | 多表查詢:https://blog.csdn.net/weixin_45606067/article/details/107368642
mybatis延遲加載 | 緩存機制詳解:https://blog.csdn.net/weixin_45606067/article/details/107368706
mybatis 注解開發版:https://blog.csdn.net/weixin_45606067/article/details/107368743
mybatis 逆向工程的使用:https://blog.csdn.net/weixin_45606067/article/details/107368781
pageHelper分頁技術:https://blog.csdn.net/weixin_45606067/article/details/107368847
如果有收獲!!! 希望老鐵們來個三連,點贊、收藏、轉發
創作不易,别忘點個贊,可以讓更多的人看到這篇文章,順便鼓勵我寫出更好的部落格