目录
【MyBatis】
【概述】
MyBatis 是一款优秀的持久层框架,用于简化 JDBC 开发
【持久层】
- 负责将数据到保存到数据库的那一层代码
- JavaEE三层架构:表现层、业务层、持久层
【框架】
- 框架就是一个半成品软件,是一套可重用的、通用的、软件基础代码模型
- 在框架的基础之上构建软件编写更加高效、规范、通用、可扩展
【MyBatis——项目示例】
查询User表中的所有数据
- 创建user表,添加数据
- 创建模块,导入坐标
<?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>org.example</groupId> <artifactId>mybatis_demo</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <!--mybatis 依赖--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.5</version> </dependency> <!--mysql 驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.32</version> </dependency> </dependencies> </project>
- 编写 MyBatis 核心配置文件 -- > 替换连接信息 解决硬编码问题
<?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.jdbc.Driver"/> <property name="url" value="jdbc:mysql:///自己数据库的表名?useSSL=false"/> <property name="username" value="自己的MySQL用户名"/> <property name="password" value="自己的MySQL密码"/> </dataSource> </environment> </environments> <mappers> <!--加载sql映射文件--> <mapper resource="UserMapper.xml"/> </mappers> </configuration>
- 编写 SQL 映射文件 --> 统一管理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"> <!-- namespace:名称空间 --> <mapper namespace="test"> <select id="selectAll" resultType="com.itheima.pojo.User"> select id,username,password,gender,addr from tb_user; </select> </mapper>
- 定义POJO类
//标准的JavaBean类 public class User { private Integer id; private String username; private String password; private String gender; private String address; public User() { } public User(Integer id, String username, String password, String gender, String address) { this.id = id; this.username = username; this.passwords = passwords; this.gender = gender; this.address = address; } public Integer getId() { return id; } public void setId(Integer 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; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + ", gender='" + gender + '\'' + ", address='" + address + '\'' + '}'; } }
- 加载核心配置文件,获取 SqlSessionFactory 对象
//加载核心配置文件,获取 SqlSessionFactory 对象 String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
- 获取 SqlSession 对象,执行 SQL 语句
//获取SqlSession对象,执行sql SqlSession sqlSession = sqlSessionFactory.openSession(); //执行sql List<User> users = sqlSession.selectList("test.selectAll"); System.out.println(users);
- 释放资源
//释放资源 sqlSession.close();
【Mapper代理开发】
【目的】
- 解决原生方式中的硬编码
- 简化后期执行SQL
【步骤】——在上述示例项目中改动
- 定义与SQL映射文件同名的Mapper接口,并且将Mapper接口和SQL映射文件放置在同一目录下
- 设置SQL映射文件的namespace属性为Mapper接口全限定名
<!-- namespace:名称空间 --> <mapper namespace="com.itheima.mapper.UserMapper"> <select id="selectAll" resultType="com.itheima.pojo.User"> select id,username,password,gender,addr from tb_user; </select> </mapper>
- 在 Mapper 接口中定义方法,方法名就是SQL映射文件中sql语句的id,并保持参数类型和返回值类型一致
public interface UserMapper { List<User> selectAll(); }
<select id="selectAll" resultType="com.itheima.pojo.User"> select id,username,password,gender,addr from tb_user; </select>
- 通过 SqlSession 的 getMapper方法获取 Mapper接口的代理对象
//获取SqlSession对象,执行sql SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
- 调用对应方法完成sql的执行
//执行sql List<User> users = userMapper.selectAll(); System.out.println(users);
【注意】:
- 在resources下创建package多级文件夹,每一级用分隔符(/)隔开
- 如果Mapper接口名称和SQL映射文件名称相同,并在同一目录下,则可以使用包扫描的方式简化SQL映射文件的加载,代码如下:
<mappers>
<!--Mapper代理开发 加载sql映射文件-->
<package name="com/itheima/mapper"/>
</mappers>
【MyBatis核心配置文件】
【核心配置文件的顶层结构】
【注意】:
- 类型别名(typeAliases)
<typeAliases>
<package name="com.itheima.pojo"/>
</typeAliases>
- 配置各个标签时,需要遵守前后顺序
【MyBatis实现数据库增删改查】
【利用配置文件完成】
【步骤】
一、准备环境
- 数据库表 tb_brand
- 实体类 Brand
- 测试用例
- 安装 MyBatisX 插件
【MyBatisX插件】:是一款基于 IDEA 的快速开发插件,为效率而生。
【功能】
- XML 和 接口方法 相互跳转
- 根据接口方法生成 statement
二、功能实现
1.查询所有数据
(1)编写接口方法: Mapper接口
- 参数:无
- 结果:List<Brand>
//Mapper接口
List<Brand> selectAll();
(2)编写 SQL语句: SQL映射文件:
<!--SQL映射文件-->
<!--
查询所有数据
-->
<select id="selectAll" resultType="brand">
select * from tb_brand;
</select>
(3)执行方法,测试
【注意】:实体类属性名 和 数据库表列名 不一致,不能自动封装数据
resultMap:定义<resultMap> 完成不一致的属性名和列名的映射
方法:1.定义<resultMap>标签
2.在<select>标签中,使用resultMap属性替换resultType
例:
<!--Mapper.xml-->
<!--
namespace:名称空间
-->
<mapper namespace="com.itheima.mapper.BrandMapper">
<!--
id:唯一标识
type:映射的类型,支持别名
-->
<resultMap id="brandResultMap" type="brand">
<!--
id:完成主键字段的映射
column:表的列明
property:实体类的属性名
result:完成一般字段的映射
-->
<result column="brand_name" property="brandName"/>
<result column="company_name" property="companyName"/>
</resultMap>
<select id="selectAll" resultMap="brandResultMap">
select id, brand_name, company_name, ordered, description, status
from tb_brand;
</select>
//Mapper接口
//查询所有数据
List<Brand> selectAll();
//测试类
public void testSelectAll() throws IOException {
//加载核心配置文件,获取 SqlSessionFactory 对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取SqlSession对象,执行sql
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取Mapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//执行sql
List<Brand> brands = brandMapper.selectAll();
System.out.println(brands);
//释放资源
sqlSession.close();
}
2.查看详情
(1)编写接口方法: Mapper接口
- 参数:id
- 结果:Brand
//Mapper接口
Brand selectById(int id);
(2)编写 SQL语句: SQL映射文件
<!--SQL映射文件>
<!--
查看详情
-->
<select id="selectById" parameterType="int" resultType="brand">
select * from tb_brand where id = #{id};
</select>
(3)执行方法,测试
例:
<!--Mapper.xml-->
<!--
namespace:名称空间
-->
<mapper namespace="com.itheima.mapper.BrandMapper">
<!--
id:唯一标识
type:映射的类型,支持别名
-->
<resultMap id="brandResultMap" type="brand">
<!--
id:完成主键字段的映射
column:表的列明
property:实体类的属性名
result:完成一般字段的映射
-->
<result column="brand_name" property="brandName"/>
<result column="company_name" property="companyName"/>
</resultMap>
<select id="selectById" resultMap="brandResultMap">
select id, brand_name, company_name, ordered, description, status
from tb_brand
where id = #{id};
<!--
#{}:会将其替换为?,为防止SQL注入
${}:拼sql,会存在SQL注入
-->
</select>
//Mapper接口
//查看详情
Brand selectById(int id);
//测试类
public void testSelectById() throws IOException {
//接受id
int id = 1;
//加载核心配置文件,获取 SqlSessionFactory 对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取SqlSession对象,执行sql
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取Mapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//执行sql
Brand brand = brandMapper.selectById(id);
System.out.println(brand);
//释放资源
sqlSession.close();
}
【注意】
1.参数占位符:
1)#{}:执行SQL时,会将#{}占位符替换为?,将来自动设置参数值
2)${}:拼SQL。会存在SQL注入问题
3)使用时机:
参数传递,都使用#{}
如果要对表名、列名进行动态设置,只能使用${}进行sql拼接。
2. parameterType:
1)用于设置参数类型,该参数可以省略
3. SQL 语句中特殊字符处理:
1)转义字符
2)<![CDATA[ 内容 ]]>:CD提示
3.条件查询
1.多条件查询——动态条件
(1)编写接口方法: Mapper接口
- 参数:所有查询条件
- 结果:List<Brand>
//Mapper接口(三种方式)
//1.散装参数:如果方法中有多个参数,需要使用@Param("SQL参数占位符名称")
List<Brand> selectByCondition(@Param("status")int status, @Param("companyName") String companyName, @Param("brandName") String brandName);
//2.对象参数:对象的属性名称要和参数占位符名称一致
List<Brand> selectByCondition(Brand brand);
//3.map集合参数
List<Brand> selectByCondition(Map map);
(2)编写 SQL语句: SQL映射文件
SQL语句会随着用户的输入或者外部条件的变化而变化,称为动态SQL
<!--SQL映射文件-->
<!--
多条件查询-动态
-->
<select id="selectByCondition" resultMap="brandResultMap">
select id, brand_name, company_name, ordered, description, status
from tb_brand
<!--where 1=1-->
<where>
<if test="status != null">
and status = #{status}
</if>
<if test="companyName != null and companyName !='' ">
and company_name like #{companyName}
</if>
<if test="brandName != null and brandName !='' ">
and brand_name like #{brandName}
</if>
</where>
</select>
(3)执行方法,测试
例:
<!--Mapper.xml>
<!--
namespace:名称空间
-->
<mapper namespace="com.itheima.mapper.BrandMapper">
<!--
id:唯一标识
type:映射的类型,支持别名
-->
<resultMap id="brandResultMap" type="brand">
<!--
id:完成主键字段的映射
column:表的列明
property:实体类的属性名
result:完成一般字段的映射
-->
<result column="brand_name" property="brandName"/>
<result column="company_name" property="companyName"/>
</resultMap>
<!--
多条件查询-动态
-->
<select id="selectByCondition" resultMap="brandResultMap">
select id, brand_name, company_name, ordered, description, status
from tb_brand
<!--where 1=1-->
<where>
<if test="status != null">
and status = #{status}
</if>
<if test="companyName != null and companyName !='' ">
and company_name like #{companyName}
</if>
<if test="brandName != null and brandName !='' ">
and brand_name like #{brandName}
</if>
</where>
</select>
//Mapper接口
//多条件查询(三种方式,后两种需要封装对象)
List<Brand> selectByCondition(@Param("status")int status, @Param("companyName") String companyName, @Param("brandName") String brandName);
List<Brand> selectByCondition(Brand brand);
List<Brand> selectByCondition(Map map);
//测试类
public void testSelectByCondition() throws IOException {
//接受参数
int status = 1;
String companyName = "华为";
String brandName = "华为";
//处理参数
companyName="%"+companyName+"%";
brandName="%"+brandName+"%";
//封装对象
//Brand对象
/* Brand brand=new Brand();
brand.setStatus(status);
brand.setBrandName(brandName);
brand.setCompanyName(companyName);*/
//Map对象
/* Map map=new HashMap();
map.put("status",status);
map.put("companyName",companyName);
map.put("brandName",brandName);*/
//加载核心配置文件,获取 SqlSessionFactory 对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取SqlSession对象,执行sql
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取Mapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//执行sql
List<Brand> brands = brandMapper.selectByCondition(status, companyName, brandName);
//List<Brand> brands = brandMapper.selectByCondition(brand);
//List<Brand> brands = brandMapper.selectByCondition(map);
System.out.println(brands);
//释放资源
sqlSession.close();
}
【注意】
if:用于判断参数是否有值,使用test属性进行条件判断
存在的问题:第一个条件不需要逻辑运算符
解决方案:
1) 使用恒等式让所有条件格式都一样
2) <where> 标签替换 where 关键字
2、单条件查询——动态查询
从多个条件中选择一个
(1)编写接口方法: Mapper接口
- 参数:所有查询条件
- 结果:Brand
//单条件查询
List<Brand> selectByConditionSingle(Brand brand);
(2)编写 SQL语句: SQL映射文件
<!--SQL映射文件-->
<!--
单条件查询-动态
-->
<select id="selectByConditionSingle" resultMap="brandResultMap">
select id, brand_name, company_name, ordered, description, status from tb_brand
<where>
<choose><!--相当于switch-->
<when test="status != null"><!--相当于case-->
status = #{status}
</when>
<when test="companyName != null and companyName !='' ">
company_name like #{companyName}
</when>
<when test="brandName != null and brandName !='' ">
brand_name like #{brandName}
</when>
</choose>
</where>
</select>
(3)执行方法,测试
例:
<!--Mapper.xml-->
<!--
namespace:名称空间
-->
<mapper namespace="com.itheima.mapper.BrandMapper">
<!--
id:唯一标识
type:映射的类型,支持别名
-->
<resultMap id="brandResultMap" type="brand">
<!--
id:完成主键字段的映射
column:表的列明
property:实体类的属性名
result:完成一般字段的映射
-->
<result column="brand_name" property="brandName"/>
<result column="company_name" property="companyName"/>
</resultMap>
<!--
单条件查询-动态
-->
<select id="selectByConditionSingle" resultMap="brandResultMap">
select id, brand_name, company_name, ordered, description, status from tb_brand
<where>
<choose><!--相当于switch-->
<when test="status != null"><!--相当于case-->
status = #{status}
</when>
<when test="companyName != null and companyName !='' ">
company_name like #{companyName}
</when>
<when test="brandName != null and brandName !='' ">
brand_name like #{brandName}
</when>
</choose>
</where>
</select>
//Mapper接口
//单条件查询
List<Brand> selectByConditionSingle(Brand brand);
//测试类
public void testSelectByConditionSingle() throws IOException {
//接受参数
Integer status = 1;
String companyName = "华为";
String brandName = "华为";
//处理参数
companyName="%"+companyName+"%";
brandName="%"+brandName+"%";
//封装对象
Brand brand=new Brand();
brand.setStatus(status);
brand.setBrandName(brandName);
brand.setCompanyName(companyName);
//加载核心配置文件,获取 SqlSessionFactory 对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取SqlSession对象,执行sql
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取Mapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//执行sql
List<Brand> brands = brandMapper.selectByConditionSingle(brand);
System.out.println(brands);
//释放资源
sqlSession.close();
}