Mybatis:
实体类
mapper接口
mapper.xml配置文件
applicationContext.xml
配置连接数据库的驱动,URL,账号和密码
扫描xml配置文件
扫描mapper类

​ 测试类

从 XML 中构建 SqlSessionFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?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>

对 MyBatis 系统的核心设置,获取数据库连接实例的数据源(DataSource)和决定事务作用域和控制方式的事务管理器(TransactionManager)

1
2
3
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先定制的 Configuration 的实例构建出 SqlSessionFactory 的实例。

可以使用任意的输入流(InputStream)实例,MyBatis 包含一个名叫 Resources 的工具类。

从 SqlSessionFactory 中获取 SqlSession

1
2
3
try (SqlSession session = sqlSessionFactory.openSession()) {
Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
}

更简洁的方式——使用正确描述每个语句的参数和返回值的接口(比如 BlogMapper.class)

例如:

1
2
3
4
try (SqlSession session = sqlSessionFactory.openSession()) {
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);
}//不依赖于字符串字面值,更安全

已映射的 SQL 语句

一个语句既可以通过 XML 定义,也可以通过注解定义。

通过xml方式定义语句:

1
2
3
4
5
6
7
8
9
<?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="org.mybatis.example.BlogMapper">
<select id="selectBlog" resultType="Blog">
select * from Blog where id = #{id}
</select>
</mapper>

使用 Java 注解来配置:

1
2
3
4
5
package org.mybatis.example;
public interface BlogMapper {
@Select("SELECT * FROM blog WHERE id = #{id}")
Blog selectBlog(int id);
}

命名空间(namespaces)

作用:一个是利用更长的完全限定名(比如 “com.mypackage.MyMapper.selectAllThings)来将不同的语句隔离开来,同时也实现了你上面见到的接口绑定

作用域(Scope)和生命周期(重要)

SqlSessionFactoryBuilder

这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但是最好还是不要让其一直存在,以保证所有的 XML 解析资源可以被释放给更重要的事情。

SqlSessionFactory

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏味道(bad smell)”。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。

SqlSession

每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,要考虑 SqlSession 放在一个和 HTTP 请求对象相似的作用域中。 换句话说,每次收到的 HTTP 请求,就可以打开一个 SqlSession,返回一个响应,就关闭它。这个关闭操作是很重要的,你应该把这个关闭操作放到 finally 块中以确保每次都能执行关闭。下面的示例就是一个确保 SqlSession 关闭的标准模式:

1
2
3
try (SqlSession session = sqlSessionFactory.openSession()) {
// 你的应用逻辑代码
}

在你的所有的代码中一致地使用这种模式来保证所有数据库资源都能被正确地关闭。

通过项目了解Mybatis(一)

官方中文地址:http://www.mybatis.org/mybatis-3/zh/

基础知识

jdbc开发:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
public class JdbcTest{
public static void main(String[] args){
//数据库连接
Connection connection = null;
//预编译的Statement,使用预编译的Statement可以提高数据库性能
PreparedStatement preparedStatement = null;
//结果集
ResultSet resultSet = null;

try{
//加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");

//通过驱动管理类获取数据库链接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/student?characterEncoding=utf-8", "root", "admin");
//定义sql语句 ?表示占位符(在这里表示username)
String sql = "select * from student where sno = ?";
//获取预处理statement
preparedStatement = connection.prepareStatement(sql);
//设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
preparedStatement.setString(1, "zs");
//向数据库发出sql执行查询,查询出结果集
resultSet = preparedStatement.executeQuery();
//遍历查询结果集
while(resultSet.next()){
System.out.println(resultSet.getString("sno")+" "+resultSet.getString("sname"));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//释放资源
if (resultSet!=null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(preparedStatement!=null) {
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection!=null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}

}

}

}
mybatis相比较jdbc有什么优点
  1. 数据库连接池(减少数据库关闭开启时数据库的资源浪费)

  2. SQL配置文件(减少硬编码)

    JDBC将SQL语句写到代码里,属于硬编码,非常不易维护,MyBatis可以将SQL代码写入xml中。

  3. 动态SQL语句(只专注写sql,各干各的事,专一)

  4. 映射(resultset直接转为java对象)

    JDBC需要先注册驱动和数据库信息、操作Connection、通过statement对象执行SQL,将结果返回给resultSet,JDBC的resultSet需要用户自己去读取并生成对应的POJO,MyBatis的mapper会自动将执行后的结果映射到对应的Java对象中。

Mybatis框架(重要)

  1. 是什么?

  2. 框架

入门程序

  1. 需求

    功能:根据id查询信息,实现增、删、改、查操作

  2. 环境

    java 环境 :jdk-9.0.4

    开发工具 : IDEA 2019.3

    数据库 : MySQL 5.7

    Mybatis 运行环境( jar 包)

    ​ mybatis-3.4.6.jar

    ​ MySQL 驱动包:mysql-connector-java-5.1.38.jar

  3. 工程结构

  4. entity类

    属性 – 数据库表的字段

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    package com.zp.mybatis.entity;

    import com.zp.mybatis.entity.Address;

    public class Student {
    private int sno; //编号
    private String sname; //姓名
    private int sage; //年龄
    private Address saddress; //地址,级联属性

    //getter and setter
    public int getSno() {
    return sno;
    }

    public void setSno(int sno) {
    this.sno = sno;
    }

    public String getSname() {
    return sname;
    }

    public void setSname(String sname) {
    this.sname = sname;
    }

    public int getSage() {
    return sage;
    }

    public void setSage(int sage) {
    this.sage = sage;
    }

    public Address getSaddress() {
    return saddress;
    }

    public void setSaddress(Address saddress) {
    this.saddress = saddress;
    }

    @Override
    public String toString() {
    return "Student{" +
    "sno=" + sno +
    ", sname='" + sname + '\'' +
    ", sage=" + sage +
    ", saddress=" + saddress +
    '}';
    }
    }
  5. mapper类(接口)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    package com.zp.mybatis.mapper;

    import com.zp.mybatis.entity.Student;

    public interface StudentMapper {
    /*
    * 1.方法名和 mapper.xml文件中标签的 id 值相同
    * 2.方法的 输入参数和 mapper.xml 文件中标签的 parameterType 类型一致
    * 3.方法的返回值和 mapper.xml 文件中标签的 resultType 类型一致
    * 4.无返回值时使用 void 接收
    */

    Student queryStudentByNo(int sno);
    }
  6. mapper.xml文件

    映射文件:

    1. 命名规则 xxxmapper.xml
    2. 其中写SQL
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.zp.mybatis.mapper.StudentMapper">
    <!--
    1. #{值} 8个基本类型 + String 时任意值;对象类型为属性名
    自动为 String 类型加上 ' '
    防止 sql 注入
    2. ${value} 8个基本类型 + String 时,必须为 value;对象类型时为属性名
    原样输出
    -->
    <select id="queryStudentByNo" parameterType="int" resultType="student">
    select * from student where sno = #{sno}
    </select>

    </mapper>
  7. db.properties

    1
    2
    3
    4
    5
    # 数据库配置 utf-8 不需要加 " "
    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/student?characterEncoding=UTF-8
    username=root
    password=admin
  8. applicationContext.xml

    配置数据库连接池、别名定义、db.properties文件加载、mapper.xml文件加载

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    <?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>
    <!-- 指定db.properties文件 必须放在第一位-->
    <properties resource="db.properties"/>

    <!-- 别名 指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean -->
    <typeAliases>
    <package name="com.zp.mybatis.entity"/>
    </typeAliases>

    <environments default="development">
    <environment id="development">
    <!-- 使用jdbc事务管理,事务由 Mybatis 控制-->
    <transactionManager type="JDBC"/>
    <!-- 数据库连接池,由Mybatis管理 -->
    <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>

    <!-- mapper文件包含了 SQL 代码 -->
    <mappers>
    <mapper resource="com/zp/mybatis/mapper/StudentMapper.xml"/>
    </mappers>
    </configuration>
  9. Test类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    package com.zp.mybatis.Test;

    import com.sun.javafx.tools.resource.PackagerResource;
    import com.zp.mybatis.entity.Student;
    import com.zp.mybatis.mapper.StudentMapper;
    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 MyBatisTest {
    public static void main(String[] args) throws IOException {
    queryStudentByNo();
    }

    public static void queryStudentByNo() throws IOException {
    //Mybatis 配置文件
    String resource = "applicationContext.xml";
    //得到配置文件流
    InputStream inputStream = Resources.getResourceAsStream(resource);
    //创建会话工厂,传入 Mybatis 配置文件信息
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    //通过工厂得到 SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //获取 mapper 接口类
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    //调用 mapper 接口的方法
    Student student = mapper.queryStudentByNo(1);

    System.out.println(student);
    sqlSession.close(); //释放资源
    }
    }

  1. 根据用户名模糊查询

    mapper.xml中加入:

    1
    2
    3
    4
    5
    6
    7
    <!-- 自定义条件查询 
    #{} 会自动加上‘’,所以传值时 %值%
    ${value} -- '%${value}%' 会引起sql注入
    -->
    <select id="findUserBySname" parameterType="String" resultType="student">
    select * from student where sname like #{sname}
    </select>

    mapper接口中加入:

    1
    2
    //根据 sname 模糊查询学生
    List<Student> findUserBySname(Student student);

    测试 findUserBySname:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public static void findUserBySname() throws IOException {
    String resource = "applicationContext.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

    Student student = new Student();
    //因使用 #{},所以直接在传值时加入 %%
    student.setSname("%2%");
    List<Student> students = mapper.findUserBySname(student);

    System.out.println(students);
    sqlSession.close();
    }

    注意:

    ​ 由上可知,其中一部分代码是重复的,显得程序很冗余,所以可以将其封装为一个函数。

    1
    2
    3
    4
    5
    6
    public static SqlSessionFactory createSqlSessionFactory() throws IOException {
    String resource = "applicationContext.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    return sqlSessionFactory;
    }
  1. 增加用户

    mapper接口添加:

    1
    2
    //添加用户
    void addStudent(Student student);

    mapper.xml文件添加:

    1
    2
    3
    4
    <insert id="addStudent" parameterType="Student" >
    insert into student(sname, sage)
    values(#{sname}, #{sage})
    </insert>

    测试类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public static void addStudent() throws IOException {
    //Student 类的构造方法
    Student student = new Student("ls", 18);
    //createSqlSessionFactory 方法返回一个 SqlSessionFactory
    SqlSession sqlSession = createSqlSessionFactory().openSession();

    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    mapper.addStudent(student);
    //提交事务
    sqlSession.commit();
    System.out.println("增加学生");
    sqlSession.close();
    }

    注意:不要忘记 Student 类的构造方法

  2. 更新信息

    接口类添加:

    1
    2
    //更新信息
    void updateStudent(Student student);

    mapper.xml文件添加:

    1
    2
    3
    <update id="updateStudent" parameterType="Student" >
    update student set sname = #{sname}, sage = #{sage} where sno = #{sno}
    </update>

    测试类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    //更新信息
    public static void updateStudent() throws IOException {
    //根据构造方法更新学生信息
    Student student = new Student(12, "ww", 55);

    SqlSession sqlSession = createSqlSessionFactory().openSession();
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    //调用接口的更新方法,自动映射到 mapper.xml 文件的 update 标签
    mapper.updateStudent(student);
    sqlSession.commit(); //提交事务
    sqlSession.close();
    }

  3. 删除学生

    接口类添加:

    1
    2
    //删除学生
    void deleteStudent(int sno);

    mapper.xml文件添加:

    1
    2
    3
    <delete id="deleteStudent" parameterType="int" >
    delete from student where sno = #{sno}
    </delete>

    测试类:

    1
    2
    3
    4
    5
    6
    7
    8
    public static void deleteStudent() throws IOException {
    SqlSession sqlSession = createSqlSessionFactory().openSession();
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    //调用接口的 deleteStudent 方法,自动映射到 mapper.xml 文件的 delete 标签
    mapper.deleteStudent(11);
    sqlSession.commit(); //提交事务
    sqlSession.close();
    }


评论