一、Mybatis簡介
1、Mybatis執(zhí)行步驟
- 讀取配置文件
mybatis-config.xml
,主要是獲取數(shù)據(jù)庫連接和運行環(huán)境信息 - 加載映射文件mapper.xml,也就是sql映射文件,需要在mybatis-config.xml中加載才能被執(zhí)行。
- 創(chuàng)建SqlSessionFactory
- 根據(jù)SqlSessionFactory創(chuàng)建SqlSession
- 使用SqlSession對象操作數(shù)據(jù)庫,包括增刪改查和事務(wù)提交
- 關(guān)閉SqlSession
二、Mybatis與Maven整合
1、Maven 依賴
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
2、mybatis配置文件
src/man/resources/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>
<!--數(shù)據(jù)庫環(huán)境-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/淄礦大數(shù)據(jù)平臺?characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--每一個Mapper都需要在此注冊,一下三種方式都可以-->
<mappers>
<mapper resource="Mapper.xml/SjddSjsctzMapper.xml"/>
<!--一下兩種方式要注意,存xml和存接口的文件夾名字要相同-->
<mapper class="ore.example.mapper.SjddSjsctzMapper"/>
<mapper package name="ore.example.mapper"/>
</mappers>
</configuration>
3、工具類
package org.example.utils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
// 獲取sqlSessionFactory對象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
// 獲取SqlSession實例,SqlSession包含了面向數(shù)據(jù)庫執(zhí)行SQL命令所需的所有方法
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession(true);
}
}
4、Mapper接口
package org.example.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.example.model.SjddSjsctz;
import java.util.List;
@Mapper
public interface SjddSjsctzMapper {
List<SjddSjsctz> selectAll();
}
5、Mapper.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" >
<!--namespace綁定對應(yīng)的Mapper接口-->
<mapper namespace="org.example.mapper.SjddSjsctzMapper">
<select id="selectAll" resultType="org.example.model.SjddSjsctz">
select * from sjdd_sjsctz;
</select>
</mapper>
6、mapper讀取數(shù)據(jù)
@Test
public void testMybatis() {
// 第一步:獲得SqlSession對象
SqlSession sqlSession = MybatisUtils.getSqlSession();
// 第二部:getMapper
SjddSjsctzMapper sjddSjsctzMapper = sqlSession.getMapper(SjddSjsctzMapper.class);
for (SjddSjsctz sjddSjsctz : sjddSjsctzMapper.selectAll()) {
System.out.println(sjddSjsctz);
}
// 第三步:關(guān)閉SslSession
sqlSession.close();
}
三、簡單CURD操作
1、增、刪、改、查 示例
// 一、查詢:可以傳bean、map、@param修飾的一個或多個參數(shù)、順序傳的單個或多個參數(shù)
List<SjddSjsctz> selectAll();
// 二、插入:可以傳bean、map、@param修飾的一個或多個參數(shù)、順序傳的單個或多個參數(shù)
// id自增,可以手動指定一個id傳進去,也可以不傳
int insertOne(Map<String,Object> map);
2、模糊查詢
兩種方式
// Java代碼里的模糊查詢參數(shù),傳遞通配符%%
List<User> userList = mapper.getUserLike("%李%");
select * from user where username like '#{username}';
List<User> userList = mapper.getUserLike("李");
select * from user where username like concat('%',#{username},'%');
3、批量插入
@Test
public void testInsert() throws Exception {
SqlSession sqlSession = MybatisUtils.sqlSessionFactory.openSession(ExecutorType.BATCH);
SjddSjsctzMapper mapper = sqlSession.getMapper(SjddSjsctzMapper.class);
for (int i = 0; i < 10; i++) {
User user = new User();
user.setUsername(UUID.randomUUID().toString());
user.setPassword(UUID.randomUUID().toString());
mapper.insertMany(user);
}
sqlSession.commit();
}
4、返回自增主鍵
當使用insert或update語句時,返回語句影響記錄的自增主鍵值。
-
useGenerateKeys="true/false"
這回讓MyBatis使用JDBC的getGenerateKeys方法,來取出由數(shù)據(jù)庫內(nèi)部生成的主鍵,默認false。如果設(shè)置為 true,將強制使用自動生成主鍵。 -
keyProperty="id"
,指定返回自增主鍵的值,將自增主鍵值賦予入?yún)⒅祵嶓w類的id
屬性。
User user = new User();
user.setUsername("username");
user.setPassword("password");
user.setRoles("roles");
user.setEnable((byte) 1);
int i = mapper.insertOne(user);
System.out.println(i);
System.out.println(user.getId()); // 得到返回的主鍵
int insertOne(User user);
-- 將主鍵返回給傳來的user對象的id屬性
<insert id="insertOne" parameterType="User" useGeneratedKeys="true" keyProperty="id">
insert into user(username, password,enable, roles)
values (#{username}, #{password}, #{enable}, #{roles});
</insert>
5、SQL執(zhí)行結(jié)束的返回值
- insert、delete、update語句:
用int返回類型,返回執(zhí)行的SQL語句影響的記錄條數(shù),若果是0則表示沒有做更改。
- select語句的返回值類型如下:
使用查詢語句執(zhí)行后,數(shù)據(jù)庫返回的實際類型。
- List/map
- javabean
- resultMap
6、mapper.xml接收的參數(shù)類型
(1)parameterType
- 接收單個參數(shù),參數(shù)類型為基本類型/包裝類型時,mapper.xml里的參數(shù)名可以隨便寫都能取到值:#{xx}
- 接收多個參數(shù),參數(shù)類型為基本類型/包裝類型時,寫入對應(yīng)的參數(shù)名;或者按照順序?qū)?{0}...#{n}
- 接收map、或?qū)嶓w類,mapper.xml里的參數(shù)名要和map的key或?qū)嶓w類里的屬性名相對應(yīng)。
int addUser(Map<String, Object>);
<insert id="addUser" parameterType="map">
insert into sjdd_sjsctz (id, name, password) values(#{name},#{password}) ;
</insert>
Map<String, Object> map = new HashMap<String, Object>();
map.put("name", "admin");
map.put("password", "123456");
mapper.addUser(map);
(2)parameterMap
用的比較少
7、mapper.xml返回的參數(shù)類型
這里的返回參數(shù),一般是select語句用到的返回數(shù)據(jù)的參數(shù)類型。
(1)resultType
- 返回實體類
- 返回map
- 單字段返回基礎(chǔ)類型
(2)resultMap
簡單用法是解決表字段與實體類屬性不一致的問題。
- 方式一:查詢語句起別名
<select id="selectAll" resultType="User">
select id, name, pwd as password from user;
</select>
- 方式二:返回值類型設(shè)置成:
resultMap
<!--只需要將不一致的字段進行對應(yīng),相當于返回了User,但修改了不一致的字段-->
<resultMap id="resultMap" type="User">
<result column="password" property="pwd"/>
</resultMap>
<select id="selectAll" resultMap="resultMap">
select id, name, pwd from user;
</select>
四、復(fù)雜查詢
1、動態(tài)SQL
(1)if
<select id="select" resultType="Blog">
SELECT * FROM BLOG WHERE state = 'ACTIVE'
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</select>
(2)foreach
- 查詢
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT * FROM POST P WHERE ID in
<foreach item="item" index="index" collection="list" open="(" separator="," close=")">
#{item}
</foreach>
</select>
- 批量插入
ArrayList<Object> users = new ArrayList<>();
for (int i = 0; i < 10; i++) {
User user = new User();
user.setUsername(UUID.randomUUID().toString());
user.setPassword(UUID.randomUUID().toString());
users.add(user);
}
int i = mapper.insertMany(users);
System.out.println(i);
int insertMany(List list);
<insert id="insertMany">
insert into user(username, password) values
<foreach collection="list" item="item" separator=",">
(#{item.username}, #{item.password})
</foreach>
</insert>
(3)choose、when、otherwise
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
(4)set
待補充。。。。
2、多表查詢
多表查詢,xml里返回類型需要用resultMap,自定義返回的字段,對一使用association,對多使用collection。實體類里要加入對一的屬性。
- 關(guān)聯(lián)-association【對一】
- 集合-collection 【對多】
javaType 用來指定實體類中屬性的類型
ofType 用來指定映射到List或集合中的pojo類型,泛型中的約束類型
(1)一對一
一對一的,使用resultMap和association。可以對javabean添加屬性也可以
- 假設(shè)一個Article對應(yīng)一個Author,Article里存放Author的id。在Article的實體類里,增加Author。
@Data
public class Article {
private String articleId;
private String title;
private Integer authorId;
// 加入需要關(guān)聯(lián)的實體類
private Author author;
}
- 編寫resultMap
<resultMap id="resultMap" type="Article">
<!-- 一下三條不能省略 -->
<id property="articleId" column="article_id"/>
<result property="title" column="title"/>
<result property="authorId" column="author_id"/>
<!-- 關(guān)聯(lián)的實體類屬性 -->
<association property="author">
<id property="id" column="id"/>
<result property="author" column="author"/>
</association>
</resultMap>
- 編寫查詢語句
<select id="selectOneToOne" resultMap="resultMap">
select a.author_id, a.title, a.article_id, b.id, b.author
from article a, author b where a.author_id = b.id;
</select>
(2)一對多
- 一的實體類
@Data
public class Article {
private String articleId;
private String title;
private Integer authorId;
// 加入需要關(guān)聯(lián)的實體類
private Author author;
// 需要關(guān)聯(lián)的一對多的評論
private List<Remark> remarks;
}
- resultMap
<resultMap id="resultMap" type="Article">
<id property="articleId" column="article_id"/>
<result property="title" column="title"/>
<result property="authorId" column="author_id"/>
<association property="author">
<id property="id" column="id"/>
<result property="author" column="author"/>
</association>
<collection property="remarks" ofType="Remark">
<id column="id" property="id"/>
<result property="cont" column="cont"/>
<result property="articleId" column="article_id"/>
</collection>
</resultMap>
- SQL語句
<select id="selectOneToMany" resultMap="resultMap">
select a.author_id, a.title, a.article_id, b.id, b.author, c.cont
from article a join author b on a.author_id = b.id join remark c on c.article_id = a.article_id
where a.article_id = #{id};
</select>
- 查詢結(jié)果
[Article(articleId=1, title=葵花寶典, authorId=1, author=Author(id=1, author=黃藥師), remarks=[Remark(id=1, cont=良心教程, articleId=1)])]
除了使用resultMap + collection外,也可以在程序中進行多次查詢。
(3)多對一
待補充。。。。
五、mybatis-config.xml 配置
1、屬性(properties)
這些屬性可以在外部進行配置,并可以進行動態(tài)替換。既可以在典型的 Java 屬性文件中配置這些屬性,也可以在 properties 元素的子元素中設(shè)置。例如:
mybatis-config.xml
<!--替換屬性-->
<properties resource="database.properties"/>
<!-- <properties resource="org/mybatis/example/config.properties">-->
<!-- <property name="username" value="dev_user"/>-->
<!-- <property name="password" value="F2Fa3!33TYyg"/>-->
<!-- </properties>-->
<!--數(shù)據(jù)庫環(huán)境-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
database.properties (注意,數(shù)據(jù)庫名用中文報錯)
driver = "com.mysql.cj.jdbc.Driver"
url = "jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8"
username = "root"
password = "root"
2、類型別名(typeAliases)
類型別名可為 Java 類型設(shè)置一個縮寫名字。 它僅用于 XML 配置,意在降低冗余的全限定類名書寫,例如:
- 單個別名分別配置:
<typeAliases>
<typeAlias alias="Author" type="com.example.Modle.Author"/>
<typeAlias alias="Blog" type="com.example.Modle.Blog"/>
</typeAliases>
- 掃描包整個model包
會使用包內(nèi) Bean 的首字母小寫的非限定類名來作為它的別名,首字母大寫也支持。有注解則優(yōu)先使用注解
<typeAliases>
<typeAlias alias="User" type="org.example.model.User"/>
<package name="org.example.model"/>
</typeAliases>
- 注解:
@Alias("xxx")
@Alias("author")
public class Author{
...
}
配置完別名之后,才能將resultType="com.example.Modle.Author"
變?yōu)?resultType="Author"
3、設(shè)置(settings)
(1)駝峰命名轉(zhuǎn)換
默認false,不進行轉(zhuǎn)換。開啟后將數(shù)據(jù)庫字段的column_table與實體類的columnTable進行自動對應(yīng),這樣查出來的數(shù)據(jù)才能賦給實體類。
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
(2)日志打印
- STDOUT_LOGGING
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
- LOG4J
(3)字段為null時處理
默認false,當查詢一條記錄,某個字段為null時,是否調(diào)用映射對象的 setter(map 對象時為 put)方法,默認mybatis不會處理這一字段,也就是不會調(diào)用null賦值給返回的對象。
<settings>
<setting name="callSettersOnNulls" value="true"/>
</settings>
(4)返回null的處理
默認false,當查詢到記錄,但返回行的所有列
都是null時,MyBatis默認返回 null對象,而不會創(chuàng)建返回對象,當調(diào)用返回對象的方法時,容易導(dǎo)致空指針錯誤。
當開啟這個設(shè)置時,MyBatis會創(chuàng)建返回對象,但對象是一個null實例,返回的實體類對象的所有屬性都是null。
<settings>
<setting name="returnInstanceForEmptyRow" value="true"/>
</settings>
注意:如果表為空,或者根據(jù)條件查找不到記錄,必定會返回null或空列表[]
上述設(shè)置只適用于,當mybatis查找到了表記錄,但是返回的列全是null的時候。如果返回的列,不是全部為null,則會正常創(chuàng)建返回對象。
六、緩存
1、一級緩存:
默認開啟,存在于SqlSession的生命周期中,什么是SqlSession的生命周期呢,簡單的來說,只有同一個請求才會是同一個SqlSession,那么就是說只有同一個請求我查詢第二次這個緩存才會生效。
2、二級緩存:
也稱為全局緩存,存在于SqlSessionFactory 的生命周期中,可以理解為跨sqlSession;緩存是以namespace為單位的,不同namespace下的操作互不影響,但是在多人開發(fā)的環(huán)境下,我的不同的namespace完全是有可能操作同一張表的,那么會導(dǎo)致一個namespace的數(shù)據(jù)修改了一張表,但是另一個namespace的那張表的數(shù)據(jù)緩存沒被修改,這樣查詢的數(shù)據(jù)就會錯誤。
- 開啟方式:在Mapper.xml里添加
<cache/>
即可
七、使用注解開發(fā)
@select("select * frome user")
List<User> getUsers();
@select("select * from user where id = #{id}")
User findById(@Param("id") long id);
@Insert("insert into user(id,name,password) values(#{id},#{name},#{password})")
int addUser(User user);
@Update("update user set name=#{name},password=#{password} where id = #{id}")
int updateUser(User user);
@Delete("delete from user where id = #{id}")
int delete(@Param("uid") int id);
mybatis-config.xml
<!--注解沒有xml文件,所以綁定Mapper接口-->
<mappers>
<mapper class="org.example.model.UserMapper"/>
</mappers>
八、Mybatis與Spring整合
待補充。。。。
九、Mybatis與SpringBoot整合
待補充。。。。