文章目录
1. 原始Jdbc操作的弊端
以下是原始的查询操作
//注册驱动
Class.forName("com,mysql.jdbcDriver");
//获得连接
Connection connection = Driverllanager.get(onnection( url: "jdbc:mysql:///test", user: "root", password: "123456");
//获得statement
statementPreparedStatement statement = connection.prepareStatement( sql: "select id,username,password from user");
//执行查询
ResultSet resultSet = statement .executeQuery();
//遍历结果集
while(resultSet.next()){
//封装实体
User user = new User();
user.setId(resultSet.getInt( columnLabel: "id"));
user.setUsername(resultSet .getString( columnLabel: "username"));
user.setPassword(resultSet.getString( columnLabel: "password"));
//user实体封装完毕
System.out.printIn(user);
}
//释放资源
resultSet.close();
statement .close();
connection.close();
无论是原始的查询操作、插入操作、删除操作,都需要做重复的工作:
- 注册驱动
- 获得连接
- 获得statement
- 执行查询/插入/删除…
- 释放资源
这种原始Jdbc操作的弊端是:
- 数据库创建连接、释放频繁造成系统资源浪费从而影响系统性能
- sql语句在代码中硬编码,造成代码不易维护,实际sql语句变化可能较大,sql变动需要修改java代码
- 查询操作时,需要手动将结果集的数据封装到实体中。插入操作时,需要手动将实体的数据设置到sql语句的占位符位置
2. MyBatis解决方案
应对上述问题,MyBatis可以给出对应的解决方案:
- 使用数据库连接池初始化资源
- 将sql语句抽取到xml配置文件中
- 使用反射、内省等底层技术,自动将实体与表进行属性与字段的映射
3. MyBatis代码快速入门(以查询语句为例)
文件结构
MyBatis开发步骤如下:
- 添加MyBatis坐标
- 创建user数据表
- 编写User实体类
- 编写映射文件UserMapper.xml
- 编写核心文件SqlMapper.xml
- 编写测试类
第一步:添加MyBatis坐标
添加MyBatis坐标
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
添加SQL连接的坐标
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
</dependency>
第二步:创建user数据表
这里需要安装MySQL,选择性安装Navicat(可视化界面)。
只安装MySQL用一下建表语句创建就行,可视化界面创建相对而言比较方便一些。
这里用Navicat创建了user数据表:
第三步:编写User实体类
在com.example.demo.domain
包里创建User类,通过Alt+Insert
快速创建所有的Setter和Getter方法
package com.example.demo.domain;
public class User {
int id;
String username;
String password;
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
第四步:编写映射文件UserMapper.xml
这个映射文件里边写的是SQL语句
在Resource下建立UserMapper.xml
,写入以下代码:
在写第一个标签mapper的时候注意要指定命名空间namespace
。因为可能有很多个mapper文件,每个mapper文件中可能都有“findAll”方法,指定命名空间可以快速定义到某mapper文件下的某个方法:命名空间.方法id
,与下面的语句id
组成查询的标识
select
表示选择语句,类似的还有insert
、update
等等,id
类似于SQL语句的名称,和上面的命名空间组成查询标识,resultType
指定返回值,也就是让MyBatis把返回值封装到我们创建好的User类中,指定查询结果的实体类型,两个<select>
语句中间写的是具体的SQL语句
<?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="userMapper">
<select id="findAll" resultType="com.example.demo.domain.User">
select * from user
</select>
</mapper>
其中<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
应该是一种指示xml格式的固定头,映射文件DTD约束头
第五步:编写核心文件SqlMapper.xml
编写好了SQL语句,我们还应当指定数据库的数据源,要不然代码无法运行
在Resource下建立SqlMapper.xml
,写入以下代码:
需要配置数据源环境、加载映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 数据源环境 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- 加载映射文件 -->
<mappers>
<mapper resource="mapper/UserMapper.xml"></mapper>
</mappers>
</configuration>
其中<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
应该是一种指示xml格式的固定头,这里与上面的区别就只有开始时候一个是mapper
一个是configuration
,后面一个是-mapper
一个是-config
environments
指定默认的环境名称
environment
指定当前环境名称
transactionManager
指定事务管理类型是JDBC
dataSource
指定当前数据源类型是连接池,下面的property
数据源配置的基本参数
mapper
标签的作用是加载映射,加载方式有以下几种:
第六步:编写测试类
执行以下代码,每一步具体做的都已经加了注释:
package com.example.demo;
import com.example.demo.domain.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 java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class DemoApplication {
public static void main(String[] args) throws IOException {
// 1. 创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 2. 加载SqlMapConfig.xml配置文件
InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
// 3. 创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
// 4. 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 5. 执行SqlSession对象执行查询,获取结果User
List<User> userList = sqlSession.selectList("userMapper.findAll");
System.out.println(userList);
// 6. 释放资源
sqlSession.close();
}
}
结果为:
[User{id=0, username='aaa', password='bbb'}, User{id=1, username='ccc', password='ddd'}]
4. MyBatis增删改
插入操作
在SqlMapper.xml中加入如下的内容,该内容应该在标签<mapper>
下:
其中,<insert>
表示插入操作,由于插入操作,我们应该向插入操作中传入具体需要插入的对象,即这里指定了一个parameterType
表示传入参数的类型,#{}
里边表示的是该parameterType下的具体属性
<insert id="insert" parameterType="com.example.demo.domain.User">
insert into user values(#{id},#{username},#{password})
</insert>
测试的时候,代码就使用如下部分替代上面的查询部分。只要是对数据库执行更新的相关操作,就需要使用sqlSession.commit()
提交事务
// 插入操作
// 模拟User对象
User user = new User();
user.setUsername("eee");
user.setPassword("fff");
sqlSession.insert("userMapper.insert", user);
// MyBatis执行数据库更新相关操作,需要提交事务
sqlSession.commit();
结果:
修改操作
在SqlMapper.xml中加入如下的内容,该内容应该在标签<mapper>
下:
<update id="update" parameterType="com.example.demo.domain.User">
update user set username=#{username}, password=#{password} where id=#{id}
</update>
测试代码:
// 修改操作
// 模拟User对象
User user = new User();
user.setId(2);
user.setUsername("ggg");
user.setPassword("hhh");
sqlSession.insert("userMapper.update", user);
// MyBatis执行数据库更新相关操作,需要提交事务
sqlSession.commit();
结果:
删除操作
在SqlMapper.xml中加入如下的内容,该内容应该在标签<mapper>
下:
注:Sql语句中使用#{任意字符串}
方式引用传递的单个参数
<delete id="delete" parameterType="java.lang.Integer">
delete from user where id=#{id}
</delete>
测试代码:
// 删除操作
sqlSession.insert("userMapper.delete", 2);
// MyBatis执行数据库更新相关操作,需要提交事务
sqlSession.commit();
执行后回数据库看发现被删掉了:
5. 核心文件SqlMapper.xml中引用properties文件
在上面的SqlMapper.xml文件中,我们是已经把driver、url、username、password等信息写死了,可能这些信息来自外部文件,那么这时候我们可以在其中导入properties文件。
在SqlMapper.xml的<configuration>
中加上:
<!-- 通过properties标签加载外部properties文件 -->
<properties resource="jdbc.properties"></properties>
jdbc.properties文件写如下属性:
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=123456
并将原始的SqlMapper中写死的内容使用${}
来替代,完整的SqlMapper文件如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 通过properties标签加载外部properties文件 -->
<properties resource="jdbc.properties"></properties>
<!-- 数据源环境 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<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>
<!-- 加载映射文件 -->
<mappers>
<mapper resource="mapper/UserMapper.xml"></mapper>
</mappers>
</configuration>
执行查询测试:
package com.example.demo;
import com.example.demo.domain.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 java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class DemoApplication {
public static void main(String[] args) throws IOException {
// 1. 创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 2. 加载SqlMapConfig.xml配置文件
InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
// 3. 创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
// 4. 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 5. 执行SqlSession对象执行查询,获取结果User
// 查询操作
List<User> userList = sqlSession.selectList("userMapper.findAll");
System.out.println(userList);
// 6. 释放资源
sqlSession.close();
}
}
可以正常打印出信息:
[User{id=0, username='aaa', password='bbb'}, User{id=1, username='ccc', password='ddd'}]
6. 使用typeAliases标签定义别名
在MyBatis中给我们定义了一些别名:
我们在写删除操作时,原本的配置代码是:
<delete id="delete" parameterType="java.lang.Integer">
delete from user where id=#{id}
</delete>
但是parameterType
太长了,基于上面给出的别名表,我们可以修改成以下内容同样可用:
<delete id="delete" parameterType="int">
delete from user where id=#{id}
</delete>
以上是一些简单类型可以直接进行替换,对于以下代码,如:
<select id="findAll" resultType="com.example.demo.domain.User">
select * from user
</select>
我们想将其替换成:
<select id="findAll" resultType="user">
select * from user
</select>
那么此时我们就需要使用typeAliases
来定义com.example.demo.domain.User
的别名为user
。
这个typeAliases
是写在sqlMapConfig.xml文件中的,写的时候需要注意顺序:
typeAliases
需要在properties
的后面、environments
的前面,标签中的type
指定类型,alias
指定别名:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 通过properties标签加载外部properties文件 -->
<properties resource="jdbc.properties"></properties>
<!-- 自定义别名 -->
<typeAliases>
<typeAlias type="com.example.demo.domain.User" alias="user"></typeAlias>
</typeAliases>
<!-- 数据源环境 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<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>
<!-- 加载映射文件 -->
<mappers>
<mapper resource="mapper/UserMapper.xml"></mapper>
</mappers>
</configuration>
此时,我们就可以将查询时候的resultType
写成这个别名了:
<select id="findAll" resultType="user">
select * from user
</select>
运行后会正常查询:
[User{id=0, username='aaa', password='bbb'}, User{id=1, username='ccc', password='ddd'}]
7. MyBatis相应API
SqlSession工厂构建器SqlSessionFactoryBuilder
SqlSessionFactory build(InputStream inputStream)
,通过加载mybatis的核心文件的输入流形式构建一个SqlSessionFactory
对象
// 创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 加载SqlMapConfig.xml配置文件,成为一个输入流
InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
// 输入流注入到工厂对象中,创建SqlSessionFactory对象,让工厂对象帮我们创建与数据交互的SqlSession对象
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
通过构建器创建SqlSession实例,常见的有如下两种方法:
SqlSession sqlSession = sqlSessionFactory.openSession();
SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
SqlSession会话对象
其中selectOne
就是返回一个对象
而后面的selectList
是返回多个对象
commit
和rollback
分别是提交和回滚