簡介
什麼是mybatis:mybatis是一款優秀的持久層框架,支持定製化SQL、存儲過程以及高級映射,避免了幾乎所有的JDBC代碼和手動設置參數以及獲取結果集。Mybatis可以使用簡單的XML或者註解來配置和映射原生類型、接口和Java的POJO爲數據庫中的記錄。
mybatis開始
先去mybatis官網點了這裏
第一步:引入maven
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>x.x.x</version>
</dependency>
第二步:Building SqlSessionFactory from XML(搭建SqlSessionFactory環境):
<?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>
<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>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
編寫的工具類:
官網中要求必須在類中引入:
String resource = “org/mybatis/example/mybatis-config.xml”;
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(inputStream);
這是通過Builder獲得SqlSessionFactory的方式。
工具類:
package com.mao.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;
//sqlSessionFactory --> sqlSession
public class MybatisUtil {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
String resource = "mybatis.config.xml";
InputStream inputStream = null;
inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//既然有了SqlsessionFactory,顧名思義,我們可以從中得到SqlSession實例.
//SqlSession包含了面向數據庫執行SQL命令所需要的方法
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
寫一個實體類映射數據庫中的表:
package com.mao.pojo;
import lombok.Data;
@Data
public class User {
private int id;
private String username;
private String password;
}
有了實體類就可以去定義一個數據訪問層接口:
package com.mao.dao;
import com.mao.pojo.User;
public interface UserDao {
User getUser(Integer id);
}
其具體的實體類並不用寫,而是通過指定的mapper配置文件來實現即可:
<?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.mao.dao.UserDao">
<select id="getUser" resultType="com.mao.pojo.User">
select * from user where id = #{id}
</select>
</mapper>
注意:這裏要指定mapper的命名空間,即是所對應的接口,select標籤中的id對應指定的方法名,resultType就是返回值。
注意:當sqlSession用完的時候應當關閉,否則會造成內存的浪費。
CRUD
1.namespace
namespace中的包名要和Dao/Mapper中的接口的包名一致。
UserDao接口
package com.mao.dao;
import com.mao.pojo.User;
import java.util.List;
public interface UserDao {
/**
* 通過id返回User
* @param id
* @return
*/
User getUserById(Integer id);
/**
* 返回所有User
* @return
*/
List<User> getUserList();
/**
* 添加用戶
* @param user
* @return
*/
int addUser(User user);
/**
* 更新用戶
* @param user
* @return
*/
int updateUser(User user);
/**
* 刪除指定用戶
* @param id
* @return
*/
int deleteUser(int id);
}
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 namespace="com.mao.dao.UserDao">
<select id="getUserById" resultType="com.mao.pojo.User">
select * from user where id = #{id}
</select>
<select id="getUserList" resultType="com.mao.pojo.User">
select * from study.user
</select>
<insert id="addUser" parameterType="com.mao.pojo.User">
insert into study.user(id,username,password) values (#{id},#{username},#{password})
</insert>
<update id="updateUser" parameterType="com.mao.pojo.User">
update study.user set username=#{username},password=#{password} where id=#{id}
</update>
<delete id="deleteUser">
delete from study.user where id=#{id}
</delete>
</mapper>
Junit測試
package com.mao.dao;
import com.mao.pojo.User;
import com.mao.utils.MybatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
import static org.junit.Assert.*;
public class UserDaoTest {
@Test
public void getUserById() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
try {
UserDao userDao = sqlSession.getMapper(UserDao.class);
User user = userDao.getUserById(1);
System.out.println(user);
}catch (Exception e){
e.printStackTrace();
}finally {
sqlSession.close();
}
}
@Test
public void getUserList() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
try {
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<User> userList = userDao.getUserList();
System.out.println(userList);
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
}
@Test
public void addUser() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
try {
User user = new User();
user.setId(4);
user.setUsername("張天偉");
user.setPassword("123456");
UserDao userDao = sqlSession.getMapper(UserDao.class);
int i = userDao.addUser(user);
System.out.println(i);
//這一步很關鍵,增刪改等DML是需要提交事務的
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
}
@Test
public void updateUser() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
try {
User user = new User();
user.setId(4);
user.setUsername("張地瓜");
user.setPassword("438");
UserDao userDao = sqlSession.getMapper(UserDao.class);
int i = userDao.updateUser(user);
sqlSession.commit();
System.out.println(i);
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
}
@Test
public void deleteUser(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
try {
UserDao mapper = sqlSession.getMapper(UserDao.class);
int i = mapper.deleteUser(3);
sqlSession.commit();
System.out.println(i);
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
}
}
注意
注意,要知道mysql是支持事務的,所以增刪改等DML語句需要在操作完成時提交一下事務,否則會因爲事務的ACID特性導致操作未顯示。
萬能的Map
在mybatis中使用Map的時候只需要再接口中使用Map,而在xxMapper.xml中parameterType指定爲map,就可以像一個對象一樣去使用它了。注:
1.使用Map中的參數,直接在sql中取其key即可【parameterType=map】
2.使用對象中的屬性,直接在sql中取其屬性即可【parameterType=Object】
只有一個基本類型的時候直接取該基本類型即可,多個的話就要用到map,
或者用註解,用上述的getUserById來演示一下:
Dao層接口代碼:
/**
* 用Map來演示
* @param map
* @return
*/
int getUserById2(Map<String,Object> map);
xxMapper.xml:
<select id="getUserById2" parameterType="map">
select * from user where id = #{id}
</select>
junit:
@Test
public void getUserById2() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
try {
UserDao userDao = sqlSession.getMapper(UserDao.class);
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("id",1);
User user = userDao.getUserById(1);
System.out.println(user);
}catch (Exception e){
e.printStackTrace();
}finally {
sqlSession.close();
}
}
輸出結果:
注意
這裏有兩個注意點:
1.一般公司裏如果用xml配置方式的話普遍推薦使用map,因爲那時候將會遇到有很多屬性的類,用map顯然在靈活性上比對象更好操作
2.mybatis中是以方法名爲id的,所以同一個Mapper是不支持重載的,這也是爲什麼我在上面中要將方法的名字改爲getUserById2
Mybatis的配置優化
- configuration(配置)
- properties(屬性):這些屬性都是可外部配置且可動態替換的,既可以在典型的 Java 屬性文件中配置,亦可通過 properties 元素的子元素來傳遞。相當於可以讀取配置文件的值,還可以在其中設置值,如果存在和外部文件相同的值,優先取外部的值
- settings(設置):對一些屬性進行配置
- typeAliases(類型別名):設置別名,可以減少包名的輸入,增加開發效率。可以給包起別名,也可以給類取別名:下面是給類取別人
<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
<typeAlias alias="Blog" type="domain.blog.Blog"/>
<typeAlias alias="Comment" type="domain.blog.Comment"/>
<typeAlias alias="Post" type="domain.blog.Post"/>
<typeAlias alias="Section" type="domain.blog.Section"/>
<typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>
給包取別名:
<typeAliases>
<package name="domain.blog"/>
</typeAliases>
每一個在包 domain.blog 中的 Java Bean,在沒有註解的情況下,會使用 Bean 的首字母小寫的非限定類名來作爲它的別名。 比如 domain.blog.Author 的別名爲 author;若有註解,則別名爲其註解值。
注意:如果實體類比較少推薦用第一種,如果比較多用第二種。第一種可以在配置中取別名,第二種不行,不過可以用註解來取別名。
@Alias("author")
public class Author {
...
}
如果同一個類註解和配置中都有,優先取註解。
- typeHandlers(類型處理器):無需太瞭解
- objectFactory(對象工廠):無需太瞭解
- plugins(插件):無需太瞭解
- environments(環境配置)
- environment(環境變量)
- transactionManager(事務管理器):分位jdbc和manager,服務於ejb,如果用spring完全不用配置。
- dataSource(數據源):連接數據庫所用,POOLED和UNPOOLED,有池和無池,如果是POOLED就在用完之後不會銷燬,而是放回POOLED。
- databaseIdProvider(數據庫廠商標識)
- mappers(映射器):註冊綁定我們配置的mapper.xml文件
resultMap的引用
我們在開發中可能會遇到這樣的一種情況,就是數據庫中的表字段和對應實體類的屬性名不一致,這時候查詢就會發現該屬性本來應該有值卻沒有,比如我把上面那對象中的User對象的password改爲psd,再做一次查詢得到:
這時候就要用到,resultMap了,該屬性就是可以實現把數據庫中的列名和屬性名做一個映射的效果。
代碼:
<mapper namespace="com.mao.dao.UserDao">
<resultMap id="userMap" type="user">
<result column="password" property="psd"></result>
</resultMap>
<select id="getUserById" resultType="user" resultMap="userMap">
select * from user where id = #{id}
</select>
</mapper>
實現效果: