记录一下 J2EE 的 SSM 学习
- MyBatis
- configuration
- mappers
简介
MyBatis 是持久层的一个 ORM 框架,移去了 JDBC 的繁琐操作以及 SQL
对代码的强绑定,采用 xml 的 SQL mapper 文件解决了这个问题,并能够进行从
SQL 结果到 实体类的转换
简单使用
1 2 3 4 5 6 7
| use mybatis; create table users( uid int primary key auto_increment, uname varchar(20) not null, uage int not null ); insert into users(uid,uname,uage) values(null,'张三',20),(null,'李四',18);
|
这个例子是基于 Maven
构建的,首先是配置依赖,这里是老版本了,实际上可以在 这里 搜,然后直接 copy
dependency
pom.xml
pom.xml1 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
| <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion>
<groupId>com.itheima</groupId> <artifactId>mybatistest</artifactId> <version>1.0-SNAPSHOT</version>
<dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.11</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>compile</scope> </dependency> </dependencies> <build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build>
</project>
|
这个 build part 实际上按这个目录写代码上不需要配置的
配置 MyBatis
db.properties
db.properties1 2 3 4
| mysql.driver=com.mysql.cj.jdbc.Driver mysql.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=false mysql.username=root mysql.password=mysql
|
应该不需要过多解释,数据库连接也就是这些东西
- 指定驱动
- 指定 JDBC URL,也就是 host, port 以及 database(可选)
- 用户名 + 密码
这个属性名(整个等号前面)实际上是任意的,在这个版本里还没有自动注入执行,只是为了语义
mybatis-config.xml
mybatis-config.xml1 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
| <?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"/> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${mysql.driver}"/> <property name="url" value="${mysql.url}"/> <property name="username" value="${mysql.username}"/> <property name="password" value="${mysql.password}"/> </dataSource> </environment> </environments> <mappers> <mapper resource="mapper/UserMapper.xml"/>
</mappers>
</configuration>
|
不在代码里配置,就得在 xml 里配置
<properties>
导入了我们的配置(记录的属性),随后的 <environments>
包含所有可能的环境,即不同的数据库配置,以及事务管理器配置,<dataSource>
中是主要的配置部分,将我们在 db.properties
中的属性加载过去
<mappers> 中配置了 mapper 部分,也即 SQL
到接口的映射配置,有几个 mapper 就有几条 <mapper>
environment 一个是通过 <environments> 的
default 切换,一个是代码里构建
SqlSessionFactory 的时候指定
UserMapper.xml
UserMapper.xml1 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 mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.pojo.User">
<select id="findById" parameterType="int" resultType="com.itheima.pojo.User"> select * from users where uid = #{id} </select> </mapper>
|
其中 <mapper> 中包含具体的映射关系(其实在
mybatis-config.xml
中我们就可以写这些,但是这样太耦合了,不推荐),这一元素必须要包含
namespace,这是为了解决 id
的命名空间问题,同一个 mapper 不能有相同的 id
id 是这一查询的接口名称(唯一标识)
parameterType 是传入参数类型
resultType 是传回结果类型,通常是一个
实体类,例如我们这里的 User
<select> 等标签内是一句动态解析的
SQL,不仅是参数可以动态,语句事实上也可以是动态的
关于这个参数传递,实际上对于这里 #{}
内部是任意的,这里是一个特殊情况,只有一个原子类型参数传递
对于一般情况,若传入类型直接为 实体类,那么 #{}
中的名称会直接解析为属性名,按照对象对应属性填充;若传入多个参数,且接口函数上无
@Param 注解标注,那么只能使用
#{0},#{1}
这样的顺序编号方式,按序读取参数;若传入接口函数上有注解标注或采用了 JVM
参数 -parameters
参数,则直接按函数接口上的命名对应填充
对于一个 mapper,在使用时我们更多讲它理解为一个函数,输入参数,生成 SQL
查询,返回结果,这也与他的接口设计模式相符合
User.sql
User.java1 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
| package com.itheima.pojo;
public class User { private int uid; private String uname; private int uage;
public int getUid() { return uid; }
public void setUid(int uid) { this.uid = uid; }
public String getUname() { return uname; }
public void setUname(String uname) { this.uname = uname; }
public int getUage() { return uage; }
public void setUage(int uage) { this.uage = uage; } }
|
这是实体类的定义,ORM 通过这些 getter,
setter
函数来进行提取与修改,而避免直接对类成员的访问,这符合 OOP
的思想,且有更多参数的可操作性,例如对返回格式的调整以及参数验证
调用 MyBatis
UserTest.java1 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
| package Test;
import com.itheima.pojo.User; 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 org.junit.Test;
import java.io.IOException; import java.io.Reader;
public class UserTest { @Test public void userFindByIdTest() { String resources = "mybatis-config.xml"; Reader reader = null; try { reader = Resources.getResourceAsReader(resources); } catch (IOException e) { e.printStackTrace(); } SqlSessionFactory sqlMapper = new SqlSessionFactoryBuilder().build(reader); SqlSession session = sqlMapper.openSession(); User user = session.selectOne("findById", 2); System.out.println(user.getUname()); session.close(); } }
|
我们主要看这个类方法里面的代码,首先我们通过 Resources
类的 getResourceAsReader
方法,传入本地的配置文件路径来获取一个文件流的
Reader,并通过 SqlSessionFactoryBuilder 的
build 方法构建一个 SqlSessionFactory
SqlSessionFactory 这个类是大多数 SQL 操作的开始
我们在这里首先通过 openSession 方法打开一个数据库
session(连接),再通过 session 上的 selectOne
方法通过 statemenet参数(id) 选出我们配置的 mapper
的一个接口,在这里,2
是传入参数,这只是单参数,单对象输出(One,对应的有
List)的传递方法,该方法调用 mapper 接口,返回了我们指定的类型
需要注意的一点是,有时候我们运行导入的项目会遇到找不到
mybatis-config.xml 的问题,这是因为 Java 编译很大程度靠
IDE(编译参数)的调节,有的项目没有在 pom.xml 中配置
resources
目录,会导致这一目录在编译后不被复制到编译目录中,导致这个问题发生
因此要么配置 resources,要么在 src/main/resources
目录上右键,选择 Mark Director As >
Resources Root
核心配置
mapper 语法
除去一大堆关于 mybatis-config.xml 的克苏鲁选项以及
SqlSessionFactoryBuilder,SqlSessionFactory,等的
大量api 之外,重要的其实只有 mapper 中的一些配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?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.itheima.mapper.StudentMapper"> <resultMap type="com.itheima.pojo.Student" id="studentMap"> <id property="id" column="sid"/> <result property="name" column="sname"/> <result property="age" column="sage"/> </resultMap> <select id="findAllStudent" resultMap="studentMap"> select * from t_student </select> </mapper>
|
这个配置文件中,使用了一个
resultMap,这通常用于处理当数据库字段和实体类属性名称不一致的问题,我们通过这个
map 映射字段,在一个查询中,我们指定 resultMap 参数为我们
resultMap 的 id
常用的查询类型有
<select>
<insert>
<update>
<delete>
<sql>
1 2 3 4
| <insert id="addUser" parameterType="com.itheima.pojo.User" keyProperty="uid" useGeneratedKeys="true" > insert into users(uid,uname,uage) values(#{uid},#{uname},#{uage}) </insert>
|
这个 insert 中有几个特殊的字段,分别是 keyProperty 和
useGeneratedKeys,这是用于获取指定自动增长字段的值并写回传入对象的
uid 属性中
这常在我们做注册操作时使用,在注册时,用户 id
往往自动生成,但是我们可能需要获取这些 id
进行一些后续步骤,而避免二次查询
SqlSessionFactory 封装
在一个项目中,这部分往往可以封装并复用
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
| package com.itheima.utils;
import java.io.Reader;
import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MyBatisUtils { private static SqlSessionFactory sqlSessionFactory = null;
static { try { Reader reader = Resources.getResourceAsReader("mybatis-config.xml"); sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); } catch (Exception e) { e.printStackTrace(); } }
public static SqlSession getSession() { return sqlSessionFactory.openSession(); } }
|
动态 SQL
一切都是为了不手动拼接字符串