目錄
MyBatis的概念及優缺點
MyBatis是一個半自動映射的框架。這裏所謂的"半自動"是相對於Hibernate全表映射而言的,MyBatis需要手動匹配提供POJO、SQL和映射關係,而Hibernate只需提供POJO和映射關係即可。
缺點:
MyBatis手動編寫SQL,工作量大。
優點:可以配置動態SQL並優化SQL
可以通過配置決定SQL的映射規則
支持存儲過程
對於一些複雜的和需要優化性能的項目來說,顯示使用MyBatis更加合適。
運行環境
idea:2018-2
mysql:5.6
使用maven管理jar包
數據庫名爲test,表爲emp和dept,表數據如下
MyBatis創建流程
1、利用idea建立一個maven工程,在pom.xml中引入jar包
<!--mybatis核心包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<!--mysql驅動包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.29</version>
</dependency>
<!-- 日誌文件管理包 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
避免配置文件發佈到tomcat服務器失敗,添加都build標籤裏
<!--把xml,properties配置文件強制性的部署到tomcat服務器上-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
2、在resources裏添加日誌文件log4j.porperties(文件名不可更改)
### jibie mudidi ###
log4j.rootLogger=debug, stdout,logfile
### kongzhitai ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout
### wenjian ###
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=jbit.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %l %F %p %m%n
3、在resources裏添加mybatis配置文件
編寫db.properties
jdbc_driver=com.mysql.jdbc.Driver
jdbc_url=jdbc:mysql://localhost:3306/test?characterEncoding=utf-8
jdbc_username=root
jdbc_password=root
編寫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>
<!--引入數據庫連接配置文件-->
<properties resource="db.properties"></properties>
<!--別名,可以直接使用類名,不用加全限定類名-->
<typeAliases>
<package name="cn.sdut.mybatis.po"></package>
</typeAliases>
<environments default="development">
<environment id="development">
<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>
</configuration>
4.編寫數據庫實體類
Dept
package cn.sdut.mybatis.po;
public class Dept {
private int deptno;
private String dname;
private String loc;
public Dept() {
}
public Dept(int deptno, String dname, String loc) {
this.deptno = deptno;
this.dname = dname;
this.loc = loc;
}
public int getDeptno() {
return deptno;
}
public void setDeptno(int deptno) {
this.deptno = deptno;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
public String getLoc() {
return loc;
}
public void setLoc(String loc) {
this.loc = loc;
}
@Override
public String toString() {
return "dept{" +
"deptno=" + deptno +
", dname='" + dname + '\'' +
", loc='" + loc + '\'' +
'}';
}
}
5.編寫dao接口
package cn.sdut.mybatis.dao;
import cn.sdut.mybatis.po.Dept;
import java.util.List;
public interface DeptDao {
//查詢
Dept selectById(int deptno);
//增加
int insertDept(Dept dept);
//刪除
int deleteDeptById(int deptno);
//更新
int updateDept(Dept dept);
List<Dept> selectAll();
}
6.編寫DeptDao.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://www.mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--對應哪個dao接口-->
<mapper namespace="cn.sdut.mybatis.dao.DeptDao">
<!--查詢的時候會用到resultMap-->
<resultMap id="deptMap" type="Dept">
<id column="deptno" property="deptno"></id>
<result column="dname" property="dname"></result>
<result column="loc" property="loc"></result>
</resultMap>
<!-- -查詢-->
<select id="selectById" parameterType="int" resultMap="deptMap">
select * from dept where deptno=#{deptno}
</select>
<insert id="insertDept" parameterType="Dept">
insert into dept value(null,#{dname},#{loc})
</insert>
<delete id="deleteDeptById" parameterType="int">
delete from dept where deptno=#{deptno}
</delete>
<update id="updateDept" parameterType="Dept">
update dept set dname=#{dname},loc=#{loc} where deptno=#{deptno}
</update>
<select id="selectAll" resultMap="deptMap">
select * from dept
</select>
</mapper>
在mybatis配置文件mybatis-config.xml裏,裝配dao,configuration標籤裏
<mappers>
<mapper class="cn.sdut.mybatis.dao.DeptDao"></mapper>
</mappers>
6.編寫測試類
package cn.test.test;
import cn.sdut.mybatis.dao.DeptDao;
import cn.sdut.mybatis.po.Dept;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.InputStream;
import java.util.List;
public class Test {
@org.junit.Test
public void test(){
//將主配置文件讀取轉化爲文件流
InputStream inputStream = Test.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
//獲取sqlSessionFactory工廠
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
//獲得dao對象
DeptDao deptDao = session.getMapper(DeptDao.class);
//精確查找
deptDao.selectById(10);
//插入
deptDao.insertDept(new Dept(0,"後勤部","青島"));
//刪除
deptDao.deleteDeptById(42);
//修改
deptDao.updateDept(new Dept(42,"行政部","青島"));
//查詢所有
List<Dept> list = deptDao.selectAll();
for (Dept d:list) {
System.out.println(d.toString());
}
//如果不提交,則只修改內存中的,雖然日誌返回正確,但是數據庫中的數據並沒有修改
session.commit();
}
}
運行結果
先刪除後修改竟然成功了,髒數據,成功了。
映射(*)
多對一,在多的一方添加一的一方的對象
例如:根據員工id查詢部門信息
因爲dept和emp表中都有deptno,所以Emp中吧deptno刪掉就可以了
package cn.sdut.mybatis.po;
/**
* @author:hydra
* @date:2019/11/29
*/
public class Emp {
private int id;
private String name;
private String job;
private int sal;
private Dept dept;
public Emp() {
}
public Emp(int id, String name, String job, int sal, int deptno, Dept dept) {
this.id = id;
this.name = name;
this.job = job;
this.sal = sal;
this.dept = dept;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public int getSal() {
return sal;
}
public void setSal(int sal) {
this.sal = sal;
}
@Override
public String toString() {
return "Emp{" +
"id=" + id +
", name='" + name + '\'' +
", job='" + job + '\'' +
", sal=" + sal +
", dept=" + dept +
'}';
}
}
編寫EmpDao.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://www.mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.sdut.mybatis.dao.EmpDao">
<resultMap id="empMap" type="Emp">
<id property="id" column="id"></id>
<result property="name" column="name"></result>
<result property="job" column="job"></result>
<result property="sal" column="sal"></result>
<result property="deptno" column="deptno"></result>
<!--多對一的時候用association,dept爲屬性名稱,Dept爲屬性類型-->
<association property="dept" javaType="Dept">
<!--配置屬性-->
<id column="deptno" property="deptno"></id>
<result column="dname" property="dname"></result>
<result column="loc" property="loc"></result>
</association>
</resultMap>
<insert id="insert" parameterType="Emp">
insert into emp value(null,#{name},#{job},#{sal},#{deptno})
</insert>
<!--連表查詢-->
<select id="select" resultMap="empMap">
select * from emp join dept on emp.deptno=dept.deptno where id=#{id}
</select>
</mapper>
MyBatis的使用
在使用MyBatis框架的時候,主要涉及兩個核心對象:SQLSessionFactory和SQLSession。
SQLSessionFactory
- 它是單個數據庫映射關係經過編譯後的內存鏡像,其主要作用是創建SqlSession。
- SqlSessionFactory則可以通過SqlSessionFactoryBuilder對象來創建
- 而SqlSessionFactoryBuilder則可以通過XML配置文件或一個預先定義好的Configuration實例構建出SqlSessionFactory實例。
- SqlSessionFactory是線程安全的
- SqlSessionFactory一旦被創建,整個應用執行期間都會存在。
- 如果多次創建同一個數據庫的SQLSessionFactory,name數據庫資源很容易被耗盡。
- 爲了解決這個問題,通常每一個數據庫只會對於一個SQLSessionFactory,所以構建SqlSessionFactory實例時,建議使用單例模式。
SqlSession
- 它是應用程序與持久層之間執行交互操作的一個單線程對象,其作用主要是執行持久化操作。
- SqlSession對象包含了數據庫中所有執行SQL操作的方法,由於底層封裝了JDBC連接,所以可以直接使用其實例來執行已映射的SQL語句
- SqlSession實例線程不安全,使用範圍最好在一個請求或者一個方法中
測試類
@org.junit.Test
public void test1(){
//將主配置文件讀取轉化爲文件流
InputStream inputStream = Test.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
//獲取sqlSessionFactory工廠
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
//獲得dao對象
EmpDao empDao = session.getMapper(EmpDao.class);
// empDao.insert(new Emp(0,"hydra","ceo",500000,20));
Emp emp = empDao.select(7936);
System.out.println(emp);
}
查詢成功
一對多
事例:查詢研發部所有的部門員工
修改emp
package cn.sdut.mybatis.po;
import java.util.List;
public class Dept {
private int deptno;
private String dname;
private String loc;
private List<Emp> emps;
public Dept() {
}
public Dept(int deptno, String dname, String loc) {
this.deptno = deptno;
this.dname = dname;
this.loc = loc;
}
public Dept(int deptno, String dname, String loc, List<Emp> emps) {
this.deptno = deptno;
this.dname = dname;
this.loc = loc;
this.emps = emps;
}
public int getDeptno() {
return deptno;
}
public void setDeptno(int deptno) {
this.deptno = deptno;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
public String getLoc() {
return loc;
}
public void setLoc(String loc) {
this.loc = loc;
}
public List<Emp> getEmps() {
return emps;
}
public void setEmps(List<Emp> emps) {
this.emps = emps;
}
@Override
public String toString() {
return "Dept{" +
"deptno=" + deptno +
", dname='" + dname + '\'' +
", loc='" + loc + '\'' +
", emps=" + emps +
'}';
}
}
修改EmpDao.xml
在resultMap中添加collection標籤,添加emps的屬性
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://www.mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--對應哪個dao接口-->
<mapper namespace="cn.sdut.mybatis.dao.DeptDao">
<!--查詢的時候會用到resultMap-->
<resultMap id="deptMap" type="Dept">
<id column="deptno" property="deptno"></id>
<result column="dname" property="dname"></result>
<result column="loc" property="loc"></result>
<!--一對多的時候爲collection,屬性名爲emps,ofType代表數據類型-->
<collection property="emps" ofType="Emp">
<id property="id" column="id"></id>
<result property="name" column="name"></result>
<result property="job" column="job"></result>
<result property="sal" column="sal"></result>
<result property="deptno" column="deptno"></result>
</collection>
</resultMap>
<!-- -查詢-->
<select id="selectById" parameterType="int" resultMap="deptMap">
select * from dept join emp on dept.deptno=emp.deptno where dept.deptno=#{deptno}
</select>
<insert id="insertDept" parameterType="Dept">
insert into dept value(null,#{dname},#{loc})
</insert>
<delete id="deleteDeptById" parameterType="int">
delete from dept where deptno=#{deptno}
</delete>
<update id="updateDept" parameterType="Dept">
update dept set dname=#{dname},loc=#{loc} where deptno=#{deptno}
</update>
<select id="selectAll" resultMap="deptMap">
select * from dept
</select>
</mapper>
測試類
@org.junit.Test
public void test2(){
//將主配置文件讀取轉化爲文件流
InputStream inputStream = Test.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
//獲取sqlSessionFactory工廠
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
//獲得dao對象
DeptDao deptDao = session.getMapper(DeptDao.class);
Dept dept = deptDao.selectById(20);
System.out.println(dept.getDname());
List<Emp> emps =dept.getEmps();
for (Emp emp: emps) {
System.out.println(emp);
}
}
總結:走了一遍流程,最重要的還是映射!映射!!映射!!!