Java學習路線-59:MyBatis數據持久層框架

MyBatis 第一個程序

MyBatis 是基於 Java 的數據持久層框架

持久化:數據從瞬時狀態變爲持久狀態
持久層:完成持久化工作的代碼塊 DAO

簡而言之:

MyBatis 將數據存入數據庫中,從數據庫中取數據

通過框架可以減少重複代碼,提高開發效率

MyBatis 是一個半自動化的 ORM 框架
Object Relationship Mapping

文檔:
https://mybatis.org/mybatis-3/zh/index.html

1、依賴

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.4</version>
</dependency>

2、配置數據庫

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>
    <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://127.0.0.1:3306/data"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="StudentMapper.xml"/>
    </mappers>
</configuration>

3、SQL 工廠類

package com.pengshiyu.mybatis.util;


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 MyBatisUtil {
    public static SqlSessionFactory getSqlSessionFactory() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        return sqlSessionFactory;
    }

    public static SqlSession getSqlSession() throws IOException {
        SqlSession session = getSqlSessionFactory().openSession();
        return session;
    }
}

4、創建實體類

package com.pengshiyu.mybatis.entity;

public class Student {
    private int id;
    private String name;
    private int age;

    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 int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

5、編寫 SQL 語句映射文件

StudentMapper.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.pengshiyu.mybatis.entity.StudentMapper">
    <select id="selectStudent" resultType="com.pengshiyu.mybatis.entity.Student">
        select * from students where id = #{id}
    </select>
</mapper>

6、測試

package com.pengshiyu.mybatis.test;

import com.pengshiyu.mybatis.entity.Student;
import com.pengshiyu.mybatis.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;

import java.io.IOException;

public class Demo {
    public static void main(String[] args) throws IOException {
        SqlSession session = MyBatisUtil.getSqlSession();
        Student student = session.selectOne("com.pengshiyu.mybatis.entity.StudentMapper.selectStudent", 3);
        System.out.println(student);
        session.close();
    //    Student{id=3, name='李白', age=30}
    }
}

curd 操作

StudentMapper.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.pengshiyu.mybatis.entity.StudentMapper">
    <select id="selectStudent" resultType="com.pengshiyu.mybatis.entity.Student">
        select * from students where id = #{id}
    </select>

    <select id="selectAllStudent" resultType="com.pengshiyu.mybatis.entity.Student">
        select * from students
    </select>

    <insert id="insertStudent" parameterType="com.pengshiyu.mybatis.entity.Student">
        insert into students(name, age) values(#{name}, #{age})
    </insert>

    <update id="updateStudent" parameterType="com.pengshiyu.mybatis.entity.Student">
        update students set name = #{name}, age = #{age} where id = #{id}
    </update>

    <delete id="deleteStudent">
        delete from students where id = #{id}
    </delete>
</mapper>
package com.pengshiyu.mybatis.dao;

import com.pengshiyu.mybatis.entity.Student;
import com.pengshiyu.mybatis.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;

import java.io.IOException;
import java.util.List;

public class StudentDao {
    public Student select(int id) throws IOException {
        SqlSession session = MyBatisUtil.getSqlSession();
        Student student = session.selectOne("com.pengshiyu.mybatis.entity.StudentMapper.selectStudent", id);
        session.close();
        return student;
    }

    public List<Student> selectAll() throws IOException {
        SqlSession session = MyBatisUtil.getSqlSession();
        List<Student> students = session.selectList("com.pengshiyu.mybatis.entity.StudentMapper.selectAllStudent");
        session.close();
        return students;
    }

    public int insert(Student student) throws IOException {
        SqlSession session = MyBatisUtil.getSqlSession();
        int result = session.insert("com.pengshiyu.mybatis.entity.StudentMapper.insertStudent", student);
        session.commit();
        session.close();
        return result;
    }

    public int update(Student student) throws IOException {
        SqlSession session = MyBatisUtil.getSqlSession();
        int result = session.update("com.pengshiyu.mybatis.entity.StudentMapper.updateStudent", student);
        session.commit();
        session.close();
        return result;
    }

    public int delete(int id) throws IOException {
        SqlSession session = MyBatisUtil.getSqlSession();
        int result = session.delete("com.pengshiyu.mybatis.entity.StudentMapper.deleteStudent", id);
        session.commit();
        session.close();
        return result;
    }
}

package com.pengshiyu.mybatis.test;

import com.pengshiyu.mybatis.dao.StudentDao;
import com.pengshiyu.mybatis.entity.Student;

import java.io.IOException;
import java.util.List;

public class Demo {
    public static void main(String[] args) throws IOException {
        StudentDao studentDao = new StudentDao();

        // 查詢
        Student student = studentDao.select(3);
        System.out.println(student);
        // Student{id=3, name='李白', age=30}

        // 寫入
        Student student = new Student();
        student.setName("Jack");
        student.setAge(23);
        System.out.println(studentDao.inset(student));
        // 1

        // 更新
        Student student = studentDao.select(16);
        student.setAge(33);
        student.setName("Tom");
        System.out.println(studentDao.update(student));
        // 1

        // 刪除數據
        System.out.println(studentDao.delete(12));
        // 1

        // 查詢多條數據
        List<Student> students = studentDao.selectAll();
        for(Student student: students){
            System.out.println(student);
        }
    }
}

配置文件解析

配置文件

每個數據庫對應一個 SqlSessionFactory 實例

dataSource:

  1. UNPOOLED 每次請求時打開和關閉連接
  2. POOLED 使用連接池
  3. JNDI 能在如 EJB 或應用服務器這類容器中使用

mapper 文件

namespace 命名規則:
包名+類名/包名+mapper 文件名

  1. parameterType 參數類型
  2. resultType 返回結果類型
  3. useGeneratedKeys=“true” 使用自增主鍵

配置優化

執行流程

  1. 讀取核心配置文件
  2. sqlSessionFactory 類
  3. sqlSession
  4. 執行相關操作

1、可以將數據庫配置單獨放在一個文件裏邊

db.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/data
username=root
password=123456
<?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" />

    <settings>
        <!-- 打印sql日誌 -->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

    <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="StudentMapper.xml"/>
    </mappers>

</configuration>

2、別名配置

<configuration>
    <typeAliases>
        <!-- 指定單個類的別名 -->
        <typeAlias type="com.pengshiyu.mybatis.entity.Student" alias="Student"/>

        <!-- 指定整個包下的類都是別名 -->
        <package name="com.pengshiyu.mybatis.entity"/>
    </typeAliases>

</configuration>

使用別名


<mapper namespace="com.pengshiyu.mybatis.entity.StudentMapper">
    <select id="selectAllStudent" resultType="Student">
        select * from students
    </select>
</mapper>

屬性名和列名不一致

MyBatis 會根據列名取賦值,會將列名轉爲小寫

1、爲列名指定別名

<mapper namespace="com.pengshiyu.mybatis.entity.StudentMapper">
    <select id="selectStudent" resultType="Student">
        select id, name, age as old from students where id = #{id}
    </select>
</mapper>

2、使用結果映射類型

<mapper namespace="com.pengshiyu.mybatis.entity.StudentMapper">
    <select id="selectStudent" resultMap="StudentMap">
        select id, name, age from students where id = #{id}
    </select>

    <resultMap id="StudentMap" type="Student">
        <!-- id爲主鍵 -->
        <id column="id" property="id" />

        <!-- column是數據庫表的列名,property是實體類屬性名 -->
        <result column="name" property="name"/>
        <result column="age" property="age"/>
    </resultMap>
</mapper>

分頁的實現

1、sql 中實現
如果將數據看做下標從 0 開始,那麼就是數據切片 [startIndex, pageSize)

<mapper namespace="com.pengshiyu.mybatis.entity.StudentMapper">
    <select id="selectAllStudent" parameterType="Map" resultType="Student">
        select * from students limit #{offset}, #{limit}
    </select>
</mapper>

public class StudentDao {
    public List<Student> selectAll(int currentPage, int pageSize) throws IOException {
        SqlSession session = MyBatisUtil.getSqlSession();

        Map<String, Integer> map = new HashMap<String, Integer>();
        map.put("offset", (currentPage - 1) * pageSize);
        map.put("limit", pageSize);

        List<Student> students = session.selectList(
            "com.pengshiyu.mybatis.entity.StudentMapper.selectAllStudent", map);

        session.close();
        return students;
    }

}

public class Demo {
    public static void main(String[] args) throws IOException {
        StudentDao studentDao = new StudentDao();

        // 查詢第二頁的數據,每頁2條
        List<Student> students = studentDao.selectAll(2 , 2);
        for(Student student: students){
            System.out.println(student);
        }
    }
}

2、使用 RowBounds

<mapper namespace="com.pengshiyu.mybatis.entity.StudentMapper">
    <select id="selectAllStudent"  resultType="Student">
        select * from students
    </select>
</mapper>
import org.apache.ibatis.session.RowBounds;

public class StudentDao {

    public List<Student> selectAll(int currentPage, int pageSize) throws IOException {
        SqlSession session = MyBatisUtil.getSqlSession();

        RowBounds rowBounds = new RowBounds((currentPage - 1) * pageSize, pageSize);

        List<Student> students = session.selectList(
            "com.pengshiyu.mybatis.entity.StudentMapper.selectAllStudent",
            null, rowBounds);

        session.close();
        return students;
    }

}

通過打印的日誌發現:

  1. sql 限制起始位置和返回數量,currentPage=2, pageSize=2 時返回 2 條數據
  2. RowBounds 不限制起始位置,currentPage=2, pageSize=2 時返回 4 條數據

註解開發

面向接口編程

擴展性好,分層開發中,上層不用管具體實現,

大家都遵循共同的實現,開發變得容易,規範性更好

DAO 接口

package com.pengshiyu.mybatis.dao;

import com.pengshiyu.mybatis.entity.Student;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface IStudentDao {
    @Select("select * from students")
    public List<Student> getList();
}

修改配置文件

<configuration>
    <mappers>
<!--        <mapper resource="StudentMapper.xml"/>-->
        <mapper class="com.pengshiyu.mybatis.dao.IStudentDao"/>
    </mappers>
</configuration>

測試使用

package com.pengshiyu.mybatis.test;

import com.pengshiyu.mybatis.dao.IStudentDao;
import com.pengshiyu.mybatis.dao.StudentDao;
import com.pengshiyu.mybatis.entity.Student;
import com.pengshiyu.mybatis.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;

import java.io.IOException;
import java.util.List;

public class Demo {
    public static void main(String[] args) throws IOException {

        SqlSession session =  MyBatisUtil.getSqlSession();
        IStudentDao studentDao = session.getMapper(IStudentDao.class);
        List<Student> students = studentDao.getList();
        for(Student student : students){
            System.out.println(student);
        }
    }
}

多對一的處理

多個學生 student 對一個老師 teacher

1、數據庫表設計

create table teachers(
	id int PRIMARY key auto_increment,
	name varchar(10)
);

create table students(
	id int PRIMARY key auto_increment,
	name varchar(10),
	teacher_id int
);

insert into teachers(name) values("王老師");
insert into teachers(name) values("李老師");
insert into teachers(name) values("趙老師");

insert into students(name, teacher_id) values("宋江", 1);
insert into students(name, teacher_id) values("李逵", 1);
insert into students(name, teacher_id) values("魯智深", 2);
insert into students(name, teacher_id) values("林沖", 3);
insert into students(name, teacher_id) values("高俅", 3);

2、實體類

Teacher

package com.pengshiyu.mybatis.entity;

public class Teacher {
    private int id;
    private String name;

    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;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

Student

package com.pengshiyu.mybatis.entity;

public class Student {
    private int id;
    private String name;
    private Teacher teacher;

    public Teacher getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }

    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;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", teacher=" + teacher +
                '}';
    }
}

3、映射文件

多對一處理方式:

(1)按結果嵌套

查詢一次

<mapper namespace="com.pengshiyu.mybatis.entity.StudentMapper">
    <select id="selectAllStudent" resultMap="StudentMap">
        select s.id sid, s.name sname, t.id tid, t.name tname
        from students as s
        left join teachers as t
        on s.teacher_id = t.id
    </select>

    <resultMap id="StudentMap" type="Student">
        <!-- 主鍵 -->
        <id column="sid" property="id"/>
        <result column="sname" property="name"/>

        <!-- 關聯對象-->
        <association property="teacher" javaType="Teacher">
            <id column="tid" property="id"/>
            <result column="tname" property="name"/>
        </association>
    </resultMap>


</mapper>
  1. 按查詢嵌套

會查詢 n 次,n 是 Student 數量

<mapper namespace="com.pengshiyu.mybatis.entity.StudentMapper">
    <select id="selectAllStudent" resultMap="StudentTeacher">
        select * from students
    </select>

    <resultMap id="StudentTeacher" type="Student">
        <!-- 關聯對象-->
        <association  property="teacher"  column="teacher_id"
        javaType="Teacher" select="getTeacher">
            <id column="tid" property="id"/>
            <result column="tname" property="name"/>
        </association>
    </resultMap>

    <select id="getTeacher" resultType="Teacher">
        select * from teachers where id = #{id}
    </select>
</mapper>

4、引入映射文件

mybatis-config.xml

<configuration>
    <typeAliases>
        <package name="com.pengshiyu.mybatis.entity"/>
    </typeAliases>

    <mappers>
        <mapper resource="StudentMapper.xml"/>
    </mappers>

</configuration>

5、Dao 編寫

package com.pengshiyu.mybatis.dao;

import com.pengshiyu.mybatis.entity.Student;
import com.pengshiyu.mybatis.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;

import java.io.IOException;
import java.util.List;

public class StudentDao {

    public List<Student> selectAll() throws IOException {
        SqlSession session = MyBatisUtil.getSqlSession();

        List<Student> students = session.selectList(
                "com.pengshiyu.mybatis.entity.StudentMapper.selectAllStudent");
        session.close();
        return students;
    }

}

6、測試類

package com.pengshiyu.mybatis.test;

import com.pengshiyu.mybatis.dao.StudentDao;
import com.pengshiyu.mybatis.entity.Student;

import java.io.IOException;
import java.util.List;

public class Demo {
    public static void main(String[] args) throws IOException {

        StudentDao studentDao = new StudentDao();
        List<Student> students = studentDao.selectAll();

        for(Student student: students){
            System.out.println(student);
        }
    }
}

查詢結果

Student{id=1, name='宋江', teacher=Teacher{id=1, name='王老師'}}
Student{id=2, name='李逵', teacher=Teacher{id=1, name='王老師'}}
Student{id=3, name='魯智深', teacher=Teacher{id=2, name='李老師'}}
Student{id=4, name='林沖', teacher=Teacher{id=3, name='趙老師'}}
Student{id=5, name='高俅', teacher=Teacher{id=3, name='趙老師'}}

一對多關係

Teacher

package com.pengshiyu.mybatis.entity;

import java.util.List;

public class Teacher {
    private int id;
    private String name;
    private List<Student> students;

    public List<Student> getStudents() {
        return students;
    }

    public void setStudents(List<Student> students) {
        this.students = students;
    }

    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;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", students=" + students +
                '}';
    }
}

TeacherMapper

查詢一次


<mapper namespace="com.pengshiyu.mybatis.entity.TeacherMapper">
    <select id="selectOneTeacher" resultMap="TeacherStudent">
        select t.id tid, t.name tname, s.id sid, s.name sname
        from teachers t left join students s
        on t.id = s.teacher_id
        where t.id = #{id}
    </select>

    <resultMap id="TeacherStudent" type="Teacher">
        <id column="tid" property="id"/>
        <result column="tname" property="name"/>

        <!-- 關聯集合 -->
        <collection property="students" ofType="Student">
            <id column="sid" property="id"/>
            <result column="sname" property="name"/>
        </collection>
    </resultMap>

</mapper>

查詢兩次


<mapper namespace="com.pengshiyu.mybatis.entity.TeacherMapper">
    <select id="selectOneTeacher" resultMap="TeacherStudent">
        select *
        from teachers
        where id = #{id}
    </select>

    <resultMap id="TeacherStudent" type="Teacher">

        <!-- 關聯集合 -->
        <!-- column 是外鍵 -->
        <collection property="students" column="id" ofType="Student"
                    select="getStudentByTeacherId">
        </collection>
    </resultMap>

    <select id="getStudentByTeacherId" resultType="Student">
        select * from students where teacher_id = #{id}
    </select>
</mapper>

mybatis-config.xml


<configuration>
    <typeAliases>
        <package name="com.pengshiyu.mybatis.entity"/>
    </typeAliases>

    <mappers>
        <mapper resource="TeacherMapper.xml"/>
    </mappers>
</configuration>

TeacherDao

package com.pengshiyu.mybatis.dao;

import com.pengshiyu.mybatis.entity.Student;
import com.pengshiyu.mybatis.entity.Teacher;
import com.pengshiyu.mybatis.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;

import java.io.IOException;
import java.util.List;

public class TeacherDao {

    public Teacher selectOne(int id) throws IOException {
        SqlSession session = MyBatisUtil.getSqlSession();
        Teacher teacher = session.selectOne(
                "com.pengshiyu.mybatis.entity.TeacherMapper.selectOneTeacher", id);
        session.close();
        return teacher;
    }

}

package com.pengshiyu.mybatis.test;

import com.pengshiyu.mybatis.dao.StudentDao;
import com.pengshiyu.mybatis.dao.TeacherDao;
import com.pengshiyu.mybatis.entity.Student;
import com.pengshiyu.mybatis.entity.Teacher;

import java.io.IOException;
import java.util.List;

public class Demo {
    public static void main(String[] args) throws IOException {

        TeacherDao teacherDao = new TeacherDao();
        Teacher teacher = teacherDao.selectOne(1);
        System.out.println(teacher);

        for(Student student: teacher.getStudents()){
            System.out.println(student);
        }
    }
}

輸出

Teacher{id=1, name='王老師', students=[
    Student{id=1, name='宋江', teacher=null},
    Student{id=2, name='李逵', teacher=null}
    ]
}
Student{id=1, name='宋江', teacher=null}
Student{id=2, name='李逵', teacher=null}

動態 SQL

根據不同的查詢條件,生成不同的 sql

<mapper namespace="com.pengshiyu.mybatis.entity.StudentMapper">
    <select id="selectAllStudent" resultType="Student">
        select * from students
        <where>
            <if test="name != null">
                name = #{name}
            </if>
        </where>
    </select>
</mapper>

sql:

select * from students WHERE name = ?
package com.pengshiyu.mybatis.dao;

import com.pengshiyu.mybatis.entity.Student;
import com.pengshiyu.mybatis.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class StudentDao {

    public List<Student> selectAllStudent(String name) throws IOException {
        SqlSession session = MyBatisUtil.getSqlSession();

        Map<String, String> map = new HashMap<>();
        map.put("name", name);

        List<Student> students = session.selectList(
                "com.pengshiyu.mybatis.entity.StudentMapper.selectAllStudent",
                map
        );
        session.close();
        return students;
    }

}

package com.pengshiyu.mybatis.test;

import com.pengshiyu.mybatis.dao.StudentDao;
import com.pengshiyu.mybatis.entity.Student;

import java.io.IOException;
import java.util.List;

public class Demo {
    public static void main(String[] args) throws IOException {

        StudentDao studentDao = new StudentDao();
        List<Student> students = studentDao.selectAllStudent("宋江");

        for(Student student: students){
            System.out.println(student);
        }
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章