mybatis采用 ORM 思想解決了實體和資料庫映射的問題,對 jdbc 進行了封裝,屏蔽了 jdbc api 底層通路細節,使我們不用與 jdbc api 打交道,就可以完成對資料庫的持久化操作。
ORM:對象關系映射(Object Relational Mapping),以面向對象的思想來操作資料庫
- 對象就是javabean對象
- 關系就是資料表
- javabean屬性與表字段一一對應
mybatis的兩種開發方式
- 使用原生接口
- Mapper代理實作自定義接口
Mybatis入門程式
1. pom.xml
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
<!--lombok簡化實體類編寫-->
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependencies>
<build>
<resources>
<!-- 表示編譯java源碼時,包含src/main/java和src/main/resources目錄下的xml、properties一起 -->
<!--如果mapper.xml在src/main/java目錄下,就必須做這個配置,不然編譯後會丢棄mapper.xml檔案-->
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
<directory>src/main/resources</directory>
</resources>
</build>
2. 建立Account表
create table t_account(
id int primary key auto_increment,
username varchar(11),
password varchar(11),
age int
);
3. 建立實體類Account
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Account {
private long id;
private String username;
private String password;
private int age;
}
4. 建立IAccountDao接口
接口中每一個方法都代表一個SQL語句,SQL語句寫在mapper檔案中
public interface IAccountDao {
//查詢一個使用者
Account selectAccountById(Integer id);
5. 建立SQL映射檔案
建議不同表的操作放在不同的mapper檔案中
在接口同一目錄下,建立與接口同名的檔案
IAccountDao.xml
,來編寫SQL語句
<?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">
<!--namespace命名空間:推薦使用dao接口的全限定名稱-->
<mapper namespace="dao.IAccountDao">
<!--id是要執行SQL語句的唯一辨別,推薦使用dao接口中的方法名稱
resultType:告訴mybatis,将查詢到的資料指派給哪個類的對象,使用實體類的全限定名稱
#{accountId}:占位符,表示從java程式中傳來的資料
-->
<select id="selectAccountById" resultType="domain.Account">
select * from t_account where id=#{accountId}
</select>
</mapper>
6. 建立主配置檔案
這裡連接配接資料庫的url的參數的大小寫敏感 &characterEncoding=utf-8
mybatis.xml包含了對 MyBatis 系統的核心設定,包括擷取資料庫連接配接執行個體的資料源(DataSource)以及決定事務作用域和控制方式的事務管理器(TransactionManager)
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--設定日志-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!--配置mybatis的運作環境。可以配置多個環境,選擇其中一個環境-->
<environments default="development">
<environment id="development">
<!--事務管理-->
<transactionManager type="JDBC"/>
<!--配置資料源:建立Connection對象-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/eesy?useUnicode=true&characterEncoding=utf-8"/>
<property name="username" value="ggbond"/>
<property name="password" value="xxxx"/>
</dataSource>
</environment>
</environments>
<!--指定mapper檔案的位置,進而找到SQL語句-->
<mappers>
<!--resource屬性從類路徑target/classes開始-->
<mapper resource="dao/IAccountDao.xml"></mapper>
</mappers>
</configuration>
7. 測試執行
public class MyTest {
@Test
public void testSelectAccountById() throws IOException {
//1.定義mybatis主配置檔案的位置,從類路徑開始的相對路徑
String config="mybatis.xml";
//2.使用mybatis架構的工具類Resources來讀取主配置檔案為流對象
InputStream is = Resources.getResourceAsStream(config);
//3.使用SqlSessionFactoryBuilder建立SqlSessionFactory對象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
//4.擷取sqlSession對象
SqlSession sqlSession = factory.openSession();
//5.指定要執行的SQL語句 = namespace + "." + id
String sqlId="dao.IAccountDao"+"."+"selectAccountById";
//6.通過sqlSession的方法,執行SQL語句
Account account=sqlSession.selectOne(sqlId,2);
System.out.println(account);
//7.關閉sqlSession對象
sqlSession.close();
}
注意
1. 占位符 #{}
如果傳給mybatis的是一個對象,那麼使用
#{屬性名}
占位符指派,mybatis通過get方法來擷取值
2. 事務
mybatis執行SQL語句預設是手動送出事務模式:在做insert、update、delete後需要手動送出事務
sqlSession.commit();
mybatis相關對象
1. Resources
作用:讀取類路徑中的主配置檔案為流對象
//1.定義mybatis主配置檔案的位置,從類路徑開始的相對路徑
String config="mybatis.xml";
//2.使用mybatis架構的工具類Resources來讀取主配置檔案為流對象
InputStream is = Resources.getResourceAsStream(config);
2. SqlSessionFactoryBuilder
作用:建立SqlSessionFactory對象
//3.使用SqlSessionFactoryBuilder建立SqlSessionFactory對象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
3. SqlSessionFactory
SqlSessionFactory是重量級對象:建立此對象需要使用更多的資源和時間。在項目中有一個即可(在工具類中放在靜态代碼塊内)
作用:是SqlSession的工廠,就是建立SqlSession對象。
方法:
-
:擷取一個預設的SqlSession對象, 預設是需要手工送出事務的。openSession()
-
: boolean參數表示是否自動送出事務。openSession(boolean)
true: 建立一個自動送出事務的SqlSession
false: 等同于沒有參數的openSession
4. SqlSession
SqlSession中提供所有執行SQL的方法
selectOne:執行sql語句,最多得到一行記錄,多餘1行是錯誤。
selectList:執行sql語句,傳回多行資料
selectMap:執行sql語句的,得到一個Map結果
insert:執行insert語句
update:執行update語句
delete:執行delete語句
commit:送出事務
rollback:回顧事務
注意SqlSession對象不是線程安全的(每次使用都要先去擷取新的對象), 使用的步驟:
①:在方法的内部,執行sql語句之前,先擷取SqlSession對象
②:調用SqlSession的方法,執行sql語句
③:關閉SqlSession對象,執行SqlSession.close()
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--設定日志-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!--配置mybatis的運作環境。可以配置多個環境,選擇其中一個環境-->
<environments default="development">
<environment id="development">
<!--事務管理-->
<transactionManager type="JDBC"/>
<!--配置資料源:建立Connection對象-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/eesy?useUnicode=true&characterEncoding=utf-8"/>
<property name="username" value="ggbond"/>
<property name="password" value="xxxx"/>
</dataSource>
</environment>
</environments>
<!--指定mapper檔案的位置,進而找到SQL語句-->
<mappers>
<!--resource屬性從類路徑target/classes開始-->
<mapper resource="dao/IAccountDao.xml"></mapper>
</mappers>
使用模闆和工具類簡化開發
模闆
mybatis-mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="dao接口的全限定名稱">
<!--使用insert、update、delete、select标簽寫SQL -->
mybatis-config
工具類
/**
* 工具類,建立SqlSession對象
*/
public class MyBatisUtil {
private static SqlSessionFactory factory =null;
static{
//1.定義mybatis主配置檔案的位置,檔案的類路徑
try {
//2.使用mybatis架構的工具類Resources來讀取主配置檔案為流對象
InputStream is = Resources.getResourceAsStream(config);
//3.使用SqlSessionFactoryBuilder建立SqlSessionFactory對象
factory = new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 擷取SqlSession對象的方法
* @return
*/
public static SqlSession getSqlSession(){
SqlSession sqlSession=null;
if (factory!=null){
sqlSession=factory.openSession();
return sqlSession;
使用:
@Test
public void testUtil() throws IOException {
//1.擷取SqlSession對象
SqlSession sqlSession = MyBatisUtil.getSqlSession();
//2.指定要執行的SQL語句
String sqlId="dao.IAccountDao"+"."+"insertAccount";
//3.通過sqlSession的方法,執行SQL語句
Account account = new Account(7,"琪琪","qiqi",20);
int i = sqlSession.insert(sqlId,account);
System.out.println(i);
//4.送出事務
sqlSession.commit();
//5.關閉sqlSession對象
sqlSession.close();
Mybatis的mapper代理
使用傳統開發方式
需要建立接口實作類,實作接口方法
public class AccountDaoImpl implements IAccountDao {
@Override
public Account selectAccountById(Integer id) {
String sqlId="dao.IAccountDao"+"."+"selectAccountById";
Account account = sqlSession.selectOne(sqlId, id);
//4.關閉sqlSession對象
return account;
public int insertAccount(Account account) {
return i;
public List<Account> selectAccounts() {
String sqlId="dao.IAccountDao"+"."+"selectAccounts";
List<Account> accounts = sqlSession.selectList(sqlId);
return accounts;
傳統開發方式的分析
在前面例子中自定義 Dao 接口實作類時發現一個問題:Dao 的實作類其實并沒有幹什麼實質性的工作,它僅僅就是通過 SqlSession 的相關 API 定位到映射檔案 mapper 中相應 id 的 SQL 語句,真正對 DB 進行操作的工作其實是由架構通過 mapper 中的 SQL 完成的。是以,MyBatis 架構就抛開了 Dao 的實作類,直接定位到映射檔案mapper 中的相應 SQL 語句,對 DB 進行操作。這種對 Dao 的實作方式稱為Mapper 的動态代理方式。
Mapper 代理實作資料庫操作(重點)
Mapper 動态代理方式無需程式員實作 Dao 接口。接口是由 MyBatis 結合映射檔案自動生成的動态代理實作的。
- 需要dao接口和對應的mapper檔案,不需要接口的實作類mapper檔案的要求:
-
- mapper檔案中的namespace是dao接口的全限定名稱
- mapper檔案中 标簽的id是dao接口方法名稱
- 以上操作綁定了mapper檔案是接口的實作類
- 隻需調用 SqlSession 的
方法,即可擷取指定接口的實作類對象。該方法的參數為指定 Dao 接口類的 class 值。getMapper()
//2.擷取接口的代理對象(将接口和配置檔案綁定)
IAccountDao dao = sqlSession.getMapper(IAccountDao.class);
Account account = dao.selectAccountById(1);
System.out.println(account);
映射檔案
mapper.xml
1. SQL語句中參數的傳遞
通過java代碼将參數傳入到mapper檔案中的sql語句。 參數主要是指dao接口方法的形參
parameterType(可選)
- parameterType是标簽屬性,表示接口中方法參數的類型, 屬性值是類型的全限定名或别名。
- 這個屬性是可選的,因為 MyBatis 可以推斷出具體傳入語句的參數,預設值為未設定(unset)。
- 接口中方法的參數從 java 代碼傳入到 mapper 檔案的 sql 語句。
第一個用法: java類型的全限定類型名稱 parameterType="java.lang.Integer"
第二個用法: mybatis定義的java類型的别名 parameterType="int"
parameterType:mybatis通過反射機制可以擷取 dao接口方法參數的類型, 可以不寫
<select id="selectById" parameterType="integer"
resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where id=#{studentId}
</select>
dao接口方法有一個參數
//dao接口的方法形參是一個簡單類型的
//簡單類型: java基本資料類型和String
Student selectByEmail(String email);
<!--
dao接口的方法形參是一個簡單類型的
mapper檔案,擷取這個參數值,使用#{任意字元}
-->
<select id="selectByEmail" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where email=#{studentEmail}
dao接口方法有多個參數
@Param
: 命名參數,在方法的形參前面使用的,定義參數名。這個名稱可以用在mapper檔案中。
在dao接口,方法的定義:
/*
多個簡單類型的參數
使用@Param命名參數, 注解是mybatis提供的
位置:在形參定義的前面
屬性:value 自定義的參數名稱
List<Student> selectByNameOrAge(@Param("myname") String name,
@Param("myage") Integer age);
mapper檔案:
多個簡單類型的參數.
當使用了@Param命名後,例如@Param("myname").
在mapper中,使用#{命名的參數}, 例如 #{myname}
<select id="selectByNameOrAge" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where name=#{myname} or age=#{myage}
dao接口方法參數是一個對象
方法的形參是一個java對象。這個java對象表示多個參數。使用對象的屬性作為參數使用
java對象
public class Student {
private Integer id;
private String name;
private String email;
private Integer age;
//set|get方法
public class QueryParam {
private Object p1;
private Object p2;
dao接口中的方法定義
* 一個java對象作為參數( 對象由屬性, 每個屬性有set,get方法)
List<Student> selectByObject(Student student);
List<Student> selectByQueryParam(QueryParam param);
mapper檔案
一個java對象作為方法的參數,使用對象的屬性作為參數值使用
簡單的文法: #{屬性名} , mybatis調用此屬性的getXXX()方法擷取屬性值
<select id="selectByObject" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where name=#{name} or age=#{age}
<select id="selectByQueryParam" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where name=#{p1} or age=#{p2}
<!--負責的文法格式: #{屬性名,javaType=java類型的全限定名稱,jdbcType=mybatis中定義列的資料類型}
javaType, jdbcType 的類型 MyBatis 可以檢測出來,一般不需要設定。常用格式 #{ property }-->
select id,name,email,age from student where
name=#{name,javaType=java.lang.String,jdbcType=VARCHAR}
or
age=#{age,javaType=java.lang.Integer,jdbcType=INTEGER}
2. #和$的差別
# 占位符
文法: #{字元}
mybatis處理#{} 使用jdbc對象是 PrepareStatment對象
resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where id=#{studentId}
mybatis會建立PrepareStatement對象,執行sql語句
String sql=" select id,name,email,age from student where id=?";
PrepareStatement pst = conn.prepareStatement(sql);
pst.setInt(1,1001); //傳遞參數
ResultSet rs = pst.executeQuery(); //執行sql語句
#{}特點:
1)使用的PrepareStatement對象,執行sql語句,效率高。
2)使用的PrepareStatement對象,能避免sql注入, sql語句執行更安全。
3) #{} 常常作為 列值使用的, 位于等号的右側, #{}位置的值和資料類型有關的。
$ 占位符
文法 : ${字元}
mybatis執行${}占位符的sql語句,使用Statement對象
select id,name,email,age from student where id=${studentId}
</select>
${} 表示字元串連接配接, 把sql語句的其他内容和 ${}内容使用 字元串(+) 連接配接的方式連在一起
String sql="select id,name,email,age from student where id=" + "1001";
mybatis建立Statement對象, 執行sql語句。
Statement stmt = conn.createStatement(sql);
ResultSet rs = stmt.executeQuery();
${} 的特點
1)使用Statement對象,執行sql語句,效率低
2)${}占位符的值,使用的字元串連接配接方式, 有sql注入的風險。 有代碼安全的問題
- ${} 資料是原樣使用的(傳什麼就用什麼), 不會區分資料類型。
4)${} 常用作 表名或者列名, 在能保證資料安全的情況下使用 ${}
3. 輸出結果的封裝
輸出結果的封裝:mybatis執行SQL語句,将結果集轉為java對象
1. resultType
- 在執行select時使用, 作為<select>标簽的屬性出現的。
- 表示查詢結果的類型,mysql執行sql語句,得到java對象的類型。值有兩種寫法:
-
- java類的全限定名稱
- 使用類的别名
對象類型
resultType屬性現在使用java類型的全限定名稱,表示mybatis執行sql,把ResultSet中的資料轉為Student類型的對象
# dao接口方法
Student selectById(Integer id);
# mapper檔案
<select id="selectById" resultType="com.bjpowernode.domain.Student">
mybatis會執行以下操作:
- 調用com.bjpowernode.domain.Student的無參數構造方法,建立對象
Student student = new Student(); //使用反射建立對象
- 同名的列指派給同名的屬性
student.setId( rs.getInt("id"));
student.setName(rs.getString("name"));
- 得到java對象, 如果dao接口傳回值是List集合, mybatis把student對象放入到List集合
簡單類型
基本類型和String
long countStudent();
# mapper檔案,執行sql語句,得到是一個值(一行一列)
<select id="countStudent" resultType="java.lang.Long">
select count(*) from student
Map
mybatis執行sql,把ResultSet轉為map:列名為key,列值為value
注意:如果sql執行得到一行,是可以轉為map的;但多于一行會報錯,無法轉換為map
//查詢結果傳回是一個Map
Map<Object,Object> selectMap(@Param("stuid") Integer id);
<select id="selectMap" resultType="java.util.HashMap">
select id,name,email from student where id != #{stuid}
2. resultMap(推薦)
resultMap:結果映射。可以自定義 列名 和 java對象屬性 的對應關系。常用在列名和屬性名不同的情況
用法:
1.先定義resultMap标簽,指定列名和屬性名稱對應關系
2.在select标簽使用resultMap屬性,指定上面定義的resultMap的id值
<!--使用resultMap定義列和屬性的關系-->
<!--定義resultMap
id:給resultMap的映射關系起個名稱,唯一值
type:java類型的全限定名稱
<resultMap id="customMap" type="com.bjpowernode.vo.CustomObject">
<!--定義列名和屬性名的對應-->
<!--主鍵類型使用id标簽-->
<id column="id" property="cid" />
<!--非主鍵類型使用result标簽-->
<result column="name" property="cname" />
<!--列名和屬性名相同不用定義-->
<result column="email" property="email" />
<result column="age" property="age" />
</resultMap>
<!--使用resultMap屬性,指定映射關系的id
resultMap和resultType 不能同時使用, 二選一。
<select id="selectById2" resultMap="customMap">
select id,name,email,age from student where id=#{stuid}
3. 列名和java對象屬性名稱不一樣的解決方式
- 使用resultMap: 自定義列名和屬性名稱對應關系
- 使用resultType: 使用列别名(as),讓别名和java對象屬性名稱一樣
4. 模糊查詢 like
類似于一個基本參數吧
dao接口方法
List<Student> selectLikeOne(@Param("name") String name);
mapper
<select id="selectLikeOne" resultType="com.bjpowernode.domain.Student">
select * from student where name like #{name}
執行like
@Test
public void testLikeOne(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
String name="%李%";
List<Student> students = dao.selectLikeOne(name);
sqlSession.close();
students.forEach( stu-> System.out.println(stu));
5. 自定義類的别名
mybatis提供的對java類的全限定名稱進行自定義别名
自定義别名的步驟:
1)在mybatis主配置檔案,使用 typeAliases标簽聲明别名
<typeAliases>
<!--第一種文法格式
type:java類型的全限定名稱(自定義類型)
alias:自定義别名
-->
<typeAlias type="com.bjpowernode.domain.Student" alias="stu" />
</typeAliases>
2)在mapper檔案中, resultType="别名"
resultType="别名"
<select id="selectById" parameterType="integer" resultType="stu">
全局配置檔案
config.xml
mybatis配置檔案兩大類:
- mybatis主配置檔案,提供mybatis全局設定的。包含的内容 日志, 資料源,mapper檔案位置
- mapper檔案: 寫sql語句的。 一個表一個mapper檔案
1. settings 設定标簽
settings是mybatis的全局設定,影響整個mybatis的運作。 這個設定一般使用預設值就可以了。
<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>
2. typeAliases 别名标簽
設定别名
<typeAliases>
<!--第一種文法格式
type:java類型的全限定名稱(自定義類型)
alias:自定義别名
優點: 别名可以自定義
缺點: 每個類型必須單獨定義
-->
<typeAlias type="com.bjpowernode.domain.Student" alias="stu" />
<typeAlias type="com.bjpowernode.vo.QueryParam" alias="qp" />
<!--第二種方式
name:包名, mybatis會把這個包中所有類名作為别名(不用區分大小寫)
優點:使用友善,一次給多個類定義别名
缺點: 别名不能自定義,必須是類名。
<package name="com.bjpowernode.domain" />
<package name="com.bjpowernode.vo" />
</typeAliases>
3. environments 環境标簽
environments: 環境标簽, 在他裡面可以配置多個environment
屬性: default ,必須是某個environment的id屬性值。 表示mybatis預設連接配接的資料庫
environment: 表示一個資料庫的連接配接資訊。
屬性: id 自定義的環境的辨別。 唯一值。
transactionManager:事務管理器
屬性: type 表示事務管理器的類型。
屬性值:1)JDBC: 使用Connection對象, 由mybatis自己完成事務的處理。
2) MANAGED: 管理,表示把事務的處理交給容器實作(由其他軟體完成事務的送出,復原)
dataSource: 資料源,建立的Connection對象,連接配接資料庫。
屬性: type 資料源的類型
屬性值:1) POOLED, mybatis會在記憶體中建立PooledDataSource類,管理多個Connection連接配接對象,使 用的連接配接池
2) UNPOOLED ,不使用連接配接池, mybatis建立一個UnPooledDataSource這個類, 每次執行sql 語句先建立Connection對象,再執行sql語句,最後關閉Connection
3) JNDI : java的命名和目錄服務。
<environments default="online">
<!--配置資料源: 建立Connection對象。-->
<!--driver:驅動的内容-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!--連接配接資料庫的url-->
<property name="url"
value="jdbc:mysql://localhost:3306/springdb"/>
<!--使用者名-->
<property name="username" value="root"/>
<!--密碼-->
<property name="password" value="123"/>
<!-- 項目上線後使用的資料庫 -->
<environment id="online">
<property name="username" value="admin"/>
<property name="password" value="123456"/>
4. 使用資料庫屬性配置檔案(*)
需要把資料庫的配置資訊放到一個單獨檔案中, 獨立管理。 這個檔案擴充名是 properties. 在這個檔案中,使用自定義的key=value的格式表示資料
使用步驟:
1.在resources目錄中,建立xxxx.properties
2.在檔案中,使用 key=value的格式定義資料。
例如
jdbc.url=jdbc:mysq://localhost:3306/springdb
3.在mybatis主配置檔案, 使用
properties
标簽引用外部的屬性配置檔案
4.在使用值的位置, 使用
${key}
擷取key對應的value(等号右側的值)
例子:
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/springdb?useUnicode=true&characterEncoding=utf-8
jdbc.username=root
jdbc.password=123
mybatis主配置檔案
<!--使用外部屬性配置檔案
resource:指定類路徑下的某個屬性配置檔案
<properties resource="jdbc.properties" />
<environments default="development">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</environment>
</environments>
5. mapper 标簽(*)
使用mapper指定其他mapper檔案的位置, 有兩個常用的方式:
<mappers>
<!--第一種方式, resources="mapper檔案的路徑"
優點:檔案清晰。 加載的檔案是明确的。
檔案的位置比較靈活。
缺點:檔案比較多, 代碼量會比較大, 管理難度大
<mapper resource="com/bjpowernode/dao/StudentDao.xml"/>
<mapper resource="com/bjpowernode/dao/OrderDao.xml"/>
<!--
第二種方式,使用<package>
name:包名, mapper檔案所在的包名。
特點: 把這個包中的所有mapper檔案,一次加載。
使用要求:
1. mapper檔案和dao接口在同一目錄
2. mapper檔案和dao接口名稱完全一樣。
<package name="com.bjpowernode.dao" />
<package name="com.bjpowernode.dao1" />
</mappers>
動态SQL
動态 SQL,通過 MyBatis 提供的各種标簽對條件作出判斷以實作動态拼接SQL 語句。這裡的條件判斷使用的表達式為 OGNL 表達式。常用的動态 SQL标簽有<if>、<where>、<choose/>、<foreach>等。MyBatis 的動态 SQL 語句,與 JSTL 中的語句非常相似。
動态 SQL,主要用于解決查詢條件不确定的情況:在程式運作期間,根據使用者送出的查詢條件進行查詢。送出的查詢條件不同,執行的 SQL 語句不同。若将每種可能的情況均逐一列出,對所有條件進行排列組合,将會出現大量的SQL 語句。此時,可使用動态 SQL 來解決這樣的問題。動态SQL的dao接口方法參數是對象
比較符号轉換為實體符
在 mapper 的動态 SQL 中若出現大于号(>)、小于号(<)、大于等于号(>=),小于等于号(<=)等符号,最好将其轉換為實體符号。否則,XML 可能會出現解析出錯問題。
&:
&
1. if 标簽
文法:
-
<if test="條件">sql語句</if>
- test使用對象的屬性值作為條件
<!--在mapper檔案中-->
<select id="selectStudent" resultType="com.bjpwoernode.domain.Student">
select *from student
<if test="條件">
sql語句
</if>
示例:
List<Student> selectIf(Student student);
<select id="selectIf" resultType="com.bjpowernode.domain.Student">
select * from student
where id=-1
<if test="name !=null and name!=''">
or name = #{name}
</if>
<if test="age >0">
or age < #{age}
2. where 标簽
<if/>标簽的中存在一個比較麻煩的地方:需要在 where 後手工添加 1=1的子句。因為,若 where 後的所有<if/>條件均為 false,而 where 後若又沒有 1=1 子句,則 SQL 中就會隻剩下一個空的 where,SQL 出錯。是以,在where 後,需要添加永為真子句 1=1,以防止這種情況的發生。但當資料量很大時,會嚴重影響查詢效率。
使用<where/>标簽,在有查詢條件為true時,可以自動添加上 where 子句;沒有查詢條件為true時,不會添加 where 子句。需要注意的是,第一個<if/>标簽中的SQL 片斷,可以不包含 and。不過,寫上 and 也不錯,系統會将多出的 and去掉。但其它<if/>中 SQL 片斷的 and,必須要求寫上。否則 SQL 語句将拼接出錯
<where>
<if test="條件1">sql語句1</if>
<if test="條件2">sql語句2</if>
</where>
//where
List<Student> selectWhere(Student student);
<!--where-->
<select id="selectWhere" resultType="com.bjpowernode.domain.Student">
<where>
<if test="name !=null and name!=''">
or name = #{name}
</if>
<if test="age >0">
or age < #{age}
</where>
3. foreach 循環标簽
使用foreach可以循環數組,list集合, 一般使用在in語句中
标簽屬性:
-
collection:表示循環的對象是數組,還是list集合。
如果dao接口方法的形參是數組,collection="array"
如果dao接口形參是List,collection="list"
- open:循環開始時的字元。 sql.append("(");
- close:循環結束時字元。 sql.append(")");
- item:集合成員, 自定義的變量。 Integer item = idlist.get(i);
- separator:集合成員之間的分隔符。 sql.append(",");
- #{item 的值}:擷取集合成員的值。
< foreach collection="集合類型" open="開始字元" close="結束字元" item="集合成員" separator="集合成員之間的分隔符">
#{item 的值}
</ foreach>
循環簡單類型的List
List<Student> selectForeachOne(List<Integer> idlist);
<!--foreach第一種方式, 循環簡單類型的List-->
<select id="selectForeachOne" resultType="com.bjpowernode.domain.Student">
select * from student
<if test="list !=null and list.size>0">
where id in
<foreach collection="list" open="(" close=")" separator="," item="myid">
#{myid}
</foreach>
public void testSelectForeachOne(){
//1.擷取SqlSession
SqlSession session = MyBatisUtil.getSqlSession();
//2.擷取dao的代理
StudentDao dao = session.getMapper(StudentDao.class);
List<Integer> idlist = new ArrayList<>();
idlist.add(1001);
idlist.add(1002);
idlist.add(1003);
List<Student> students = dao.selectForeachOne(idlist);
students.forEach( stu-> System.out.println("stu=="+stu));
//3.關閉SqlSession對象
session.close();
循環對象類型的list
//foreach-2
List<Student> selectForeachTwo(List<Student> studentList);
<!--foreach第二種方式, 循環的List<Student>-->
<select id="selectForeachTwo" resultType="com.bjpowernode.domain.Student">
select * from student
<if test="list != null and list.size>0">
<foreach collection="list" open="(" close=")" separator="," item="stu">
#{stu.id}
@Test
public void testSelectForeachTwo(){
List<Student> list = new ArrayList<>();
Student s1 = new Student();
s1.setId(1001);
Student s2 = new Student();
s2.setId(1002);
list.add(s1);
list.add(s2);
List<Student> students = dao.selectForeachTwo(list);
4. 代碼片段
<sql/>标簽用于定義 SQL 片斷,以便其它 SQL 标簽複用。而其它标簽使用該 SQL 片斷,需要使用<include/>子标簽。該<sql/>标簽可以定義 SQL 語句中的任何部分,是以<include/>子标簽可以放在動态 SQL 的任何位置。
<!--定義代碼片段-->
<sql id="selectStudent">
</sql>
<sql id="studentFieldList">
id,name,email
<include refid="selectStudent" />
where id=-1
or name = #{name}
</select>
<select id="selectWhere" resultType="com.bjpowernode.domain.Student">
select <include refid="studentFieldList"/> from student
<where>
<if test="name !=null and name!=''">
or name = #{name}
</if>
<if test="age >0">
or age < #{age}
</where>
分頁助手PageHelper
PageHelper做資料分頁。 在你的select語句後面加入分頁的 sql 内容, 如果你使用的mysql資料庫, 它就是在select * from student 後面加入 limit 語句。
1.加入依賴pagehelper依賴
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.10</version>
</dependency>
2.在mybatis主配置檔案, 加入plugin聲明
在<environments> 之前加入
<plugins>
<plugin interceptor ="com.github.pagehelper.PageInterceptor" />
</plugins>
3.在select語句之前,調用
PageHelper.startPage(頁碼,每頁大小)
。緊跟在這個方法後的第一個 MyBatis 查詢方法會被進行分頁
public void testSelect() throws IOException {
//擷取第 1 頁,3 條内容(頁碼從1開始)
PageHelper.startPage(1,3);
List<Student> studentList = studentDao.selectStudents();
studentList.forEach( stu -> System.out.println(stu));
對比:
- 沒有使用PageHelper
select * from student order by id
- 使用PageHelper
SELECT count(0) FROM student
select * from student order by id LIMIT ?