MyBatis
一.原生态jdbc编程中的问题总结
1.创建mysql数据
导入下边的脚本:
sql_table.sql:记录表结构
sql_data.sql:记录测试数据,在实际企业开发中,最后提供一个初始化数据脚本
2.原生态jdbc程序
使用jdbc查询mysql数据库中用户表的记录。
修改pom.xml,引入相关依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
程序代码:JdbcTest.java使用jdbc的原始方法(未经封装)实现了查询数据库表记录的操作
public class JdbcTest {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/order?characterEncoding=utf-8", "root", "root");
String sql = "select from user where username = ?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, "王五");
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
System.out.println(resultSet.getString("id") + " " + resultSet.getString("username"));
}
} 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();
}
}
}
}
}
3.问题总结
1)、数据库连接,使用时就创建,不使用立即释放,对数据库进行频繁连接开启和关闭,造成数据库资源浪费,影响数据库性能。
设想:使用数据库连接池管理数据库连接。
2)、将sql语句硬编码到java代码中,如果sql 语句修改,需要重新编译java代码,不利于系统维护。
设想:将sql语句配置在xml配置文件中,即使sql变化,不需要对java代码进行重新编译。
3)、向preparedStatement中设置参数,对占位符号位置和设置参数值,硬编码在java代码中,不利于系统维护。
设想:将sql语句及占位符号和参数全部配置在xml中。
4)、从ResultSet中遍历结果集数据时,存在硬编码,将获取表的字段进行硬编码,不利于系统维护。
设想:将查询的结果集,自动映射成java对象。
二.mybatis框架原理
1.mybatis是什么?
? mybatis是一个持久层的框架,是apache下的顶级项目。mybatis托管到goolecode下,再后来托管到github下(https://github.com/mybatis/mybatis-3/releases)。
? mybatis让程序员将主要精力放在sql上,通过mybatis提供的映射方式,自由灵活生成(半自动化,大部分需要程序员编写sql)满足需要sql语句。 mybatis可以将向 preparedStatement中的输入参数自动进行输入映射,将查询结果集灵活映射成java对象。(输出映射)
2.mybatis框架原理
1、 mybatis配置
SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。
mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。
2、 通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂
3、 由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
4、 mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
5、 Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
6、 Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。
7、 Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xRpLBkD3-1641215111304)(image/wpsPLJvK4.png)]
三.mybatis入门程序
1.工程结构
1.1 需求
根据用户id(主键)查询用户信息
根据用户名称模糊查询用户信息
添加用户
删除用户
更新用户
1.2 修改pom.xml,引入相关依赖
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
1.3 新建log4j.properties日志属性文件
mybatis默认使用log4j作为输出日志信息。
在src文件夹下,创建了resources文件夹,右击选择Mark Directory as --> resources root,在其里面创建log4j.properties文件如下:
# Global logging configuration
# 在开发环境下日志级别要设置成DEBUG,生产环境设置成info或error
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
修改pom.xml,添加日志依赖
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
1.4 新建db.properties属性文件
#mysql
db.username = root
db.password = root
db.jdbcUrl = jdbc:mysql://localhost:3306/order?characterEncoding=utf-8
db.driverClass = com.mysql.jdbc.Driver
修改pom.xml,添加mysql依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
1.5 SqlMapConfig.xml核心配置文件
SqlMapConfig.xml是mybatis核心配置文件,配置mybatis的运行环境,数据源、事务等。
在src文件夹下,创建了resources文件夹,在其里面创建SqlMapConfig.xml文件。
首先,先创建mybatis核心配置文件模版
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-15WQGLpl-1641215111309)(image/image-20200713211001576.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sisJam0u-1641215111310)(image/image-20200713211254836.png)]
<?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>
</configuration>
要求核心配置文件中,configuration所有配置必须严格按照以下顺序进行编写。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5vGnbLOq-1641215111311)(image/image-20210624155159869.png)]
其次,再新建SqlMapConfig.xml核心配置文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L9pu2OGi-1641215111311)(image/image-20200713211431635.png)]
<?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"></properties>
<typeAliases>
<package name="com.cm.entity"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${db.driverClass}" />
<property name="url" value="${db.jdbcUrl}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
</dataSource>
</environment>
</environments>
<mappers>
<package name=" " />
</mappers>
</configuration>
1.6 Mapper映射文件
若想在与同名接口同路径下创建Mapper映射文件,需要修改pom.xml。
原因是IDEA编译后默认会把resources下的文件放到target的classpath下,但是src下的只有Java文件编译生成.class文件放入classpath下,其他文件会忽略的,例如.xml文件。
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
首先,先创建mapper映射文件模版
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OA9QcZRn-1641215111312)(image/image-20200713211001576.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6BuNuEZ1-1641215111314)(image/image-20200713212326790.png)]
<?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=" ">
</mapper>
其次,再新建Mapper映射文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZdYqPANS-1641215111315)(image/image-20200713233247884.png)]
1.7 工程结构
2.根据id查询用户
2.1 创建entity.User类
User.java作为mybatis进行sql映射使用,通常属性名与数据库表字段对应
import java.util.Date;
public class User {
private int id;
private String username;
private String sex;
private Date birthday;
private String address;
public User() {
}
public User(int id, String username, String sex, Date birthday, String address) {
this.id = id;
this.username = username;
this.sex = sex;
this.birthday = birthday;
this.address = address;
}
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 getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", sex='" + sex + '\'' +
", birthday=" + birthday +
", address='" + address + '\'' +
'}';
}
}
2.2 修改映射文件UserMapper.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.cm.ch01.mapper.UserMapper">
<select id="selectUserById" parameterType="Integer" resultType="User">
select * from user where id = #{id}
</select>
</mapper>
2.3 创建UserMapper.java接口
public interface UserMapper {
public User selectUserById(Integer id);
}
2.4 在SqlMapConfig.xml中加载映射文件
在sqlMapConfig.xml中加载User.xml:
<mappers>
<package name="com.cm.ch01.mapper" />
</mappers>
2.5 新建junit测试类
1). 修改test目录,右击选择Mark Directory as -> Test Resources Root
2). 选择需要建junit测试类的接口,右击选择Go To -> Test
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vs8rMXxE-1641215111316)(image/image-20200713221414296.png)]
3). 创建UserMapperTest类,勾选需要测试的方法
4). 编写测试类
public class UserMapperTest {
private SqlSessionFactory factory;
@Before
public void setUp() throws Exception {
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
factory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void selectUserById() {
SqlSession sqlSession = factory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.selectUserById(1);
System.out.println(user);
sqlSession.close();
}
}
3.根据用户名称模糊查询用户信息
3.1 修改映射文件UserMapper.xml
<select id="selectUserByName" parameterType="String" resultType="User">
select * from user where username like CONCAT('%',#{username},'%')
</select>
3.2 修改UserMapper.java接口
public List<User> selectUserByName(String name);
3.3 修改junit测试类
@Test
public void selectUserByName() {
SqlSession sqlSession = factory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = userMapper.selectUserByName("小明");
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
4.添加用户
4.1 修改映射文件UserMapper.xml
<insert id="insertUser" parameterType="User">
<selectKey keyProperty="id" order="AFTER" resultType="Integer">
select LAST_INSERT_ID()
</selectKey>
insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
</insert>
4.2 修改UserMapper.java接口
public void insertUser(User user);
4.3 修改junit测试类
@Test
public void insertUser() throws ParseException {
SqlSession sqlSesison = factory.openSession();
UserMapper userMapper = sqlSesison.getMapper(UserMapper.class);
String str = "2019-09-09 12:12:12";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = sdf.parse(str);
User user = new User("里斯","2",date,"苏州");
userMapper.insertUser(user);
System.out.println(user);
sqlSesison.commit();
sqlSesison.close();
}
5.修改用户
5.1 修改映射文件UserMapper.xml
<update id="updateUser" parameterType="User">
update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address}
where id = #{id}
</update>
5.2 修改UserMapper.java接口
public void updateUser(User user);
5.3 修改junit测试类
@Test
public void updateUser() {
SqlSession sqlSesison = factory.openSession();
UserMapper userMapper = sqlSesison.getMapper(UserMapper.class);
User user = userMapper.selectUserById(29);
user.setUsername("李四");
userMapper.updateUser(user);
sqlSesison.commit();
sqlSesison.close();
}
6.删除用户
6.1 修改映射文件UserMapper.xml
<delete id="deleteUser" parameterType="int">
delete from user where id = #{id}
</delete>
6.2 修改UserMapper.java接口
public void deleteUser(Integer id);
6.3 修改junit测试类
@Test
public void deleteUser() {
SqlSession sqlSesison = factory.openSession();
UserMapper userMapper = sqlSesison.getMapper(UserMapper.class);
userMapper.deleteUser(29);
sqlSesison.commit();
sqlSesison.close();
}
四.SqlMapConfig-配置内容
SqlMapConfig.xml
mybatis的全局配置文件SqlMapConfig.xml,配置内容及顺序如下:
properties(属性)
settings(全局配置参数)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
? environment(环境子属性对象)
? transactionManager(事务管理)
? dataSource(数据源)
mappers(映射器)
1. properties属性
需求:
将数据库连接参数单独配置在db.properties中,只需要在SqlMapConfig.xml中加载db.properties的属性值。
在SqlMapConfig.xml中就不需要对数据库连接参数硬编码。
将数据库连接参数只配置在db.properties中,原因:方便对参数进行统一管理,其它xml可以引用该db.properties。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0wsczsgt-1641215111317)(image/wps1.jpg)]
在sqlMapConfig.xml加载属性文件:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W8OSGx3S-1641215111318)(image/wps2.jpg)]
properties特性:
注意: MyBatis 将按照下面的顺序来加载属性:
在 properties 元素体内定义的属性首先被读取。
<properties resource="db.properties">
<property name="" value="" />
</properties>
然后会读取properties 元素中resource或 url 加载的属性,它会覆盖已读取的同名属性。
最后读取parameterType传递的属性,它会覆盖已读取的同名属性。
建议:
不要在properties元素体内添加任何属性值,只将属性值定义在properties文件中。
在properties文件中(如:db.properties文件)定义属性名要有一定的特殊性,如:XXXXX.XXXXX.XXXX
2. settings全局参数配置
mybatis框架在运行时可以调整一些运行参数。比如:**开启二级缓存、开启延迟加载。**全局参数将会影响mybatis的运行行为。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n50gBhKh-1641215111318)(image/wps3.jpg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GZ8Y2gKJ-1641215111319)(image/wps4.jpg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qtEUdxIL-1641215111320)(image/wps5.jpg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hjLa8XYE-1641215111320)(image/wps6.jpg)]
3. typeAliases 别名
3.1 需求
在mapper.xml中,定义很多的statement,statement需要parameterType指定输入参数的类型、需要resultType指定输出结果的映射类型。
如果在指定类型时输入类型全路径,不方便进行开发,可以针对parameterType或resultType指定的类型定义一些别名,在mapper.xml中通过别名定义,方便开发。
3.2 mybatis默认支持别名
别名 | 映射的类型 |
---|
_byte | byte | _long | long | _short | short | _int | int | _integer | int | _double | double | _float | float | _boolean | boolean | string | String | byte | Byte | long | Long | short | Short | int | Integer | integer | Integer | double | Double | float | Float | boolean | Boolean | date | Date | decimal | BigDecimal | bigdecimal | BigDecimal |
3.3 自定义别名
批量定义别名
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dDmdcAF1-1641215111321)(image/wps9.jpg)]
4. mappers(映射配置)
批量加载mapper
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FfyH29uZ-1641215111322)(image/wps13.jpg)]
五.输入映射-parameterType
通过parameterType指定输入参数的类型,类型可以是简单类型、hashmap、pojo的自定义的包装类型。
需求
完成用户信息的综合查询,需要传入查询条件很复杂(可能包括用户信息、其它信息,比如商品、订单的)
1.传递pojo的包装类型
1.1 定义包装类型pojo
针对上边需求,建议使用自定义的包装类型的pojo。在包装类型的pojo中将复杂的查询条件包装进去。
UserQueryVo 用户包装类型 UserCustom继承User是用户的扩展类,扩展用户的信息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LS1qAHY8-1641215111322)(image/wps111.jpg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-arTlo4hi-1641215111323)(image/wps222.jpg)]
1.2 mapper.xml
在UserMapper.xml中定义用户信息综合查询(查询条件复杂,通过高级查询进行复杂关联查询)。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U4jIGxTO-1641215111323)(image/wps333.jpg)]
1.3 mapper.java
? 在接口UserMapper.java中,定义用户信息综合查询方法。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c25sjaS3-1641215111324)(image/wps444.jpg)]
1.4 测试代码
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BwRV320e-1641215111324)(image/wps555.jpg)]
2.传递hashmap类型
sql映射文件定义如下:
2.1 UserMapper.xml中
<select id="findUserByHashmap" parameterType="hashmap" resultType="user">
select from user where id=#{id} and username like '%${username}%'
</select>
上边的#{id}、%${username}% 是hashmap的key。
2.2 测试
Public void testFindUserByHashmap()throws Exception{
SqlSession session = sqlSessionFactory.openSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("id", 1);
map.put("username", "小明");
List<User>list = userMapper.findUserByHashmap(map);
session.close();
}
异常测试:
传递的map中的key和sql中解析的key不一致。
测试结果没有报错,只是通过key获取值为空。
六.输出映射-resultType及resultMap
1.resultType
使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。
如果查询出来的列名和pojo中的属性名全部不一致,没有创建pojo对象。
只要查询出来的列名和pojo中的属性有一个一致,就会创建pojo对象。
1.1 输出简单类型
1.1.1 需求
用户信息的综合查询列表总数,通过查询总数和上边用户综合查询列表才可以实现分页。
1.1.2 mapper.xml
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NzyfRgsh-1641215111325)(image/wps21.jpg)]
1.1.3 mapper.java
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L5vH7HYy-1641215111325)(image/wps22.jpg)]
1.1.4 测试代码
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n7Nv1S4e-1641215111326)(image/wps23.jpg)]
1.1.5 小结
查询出来的结果集只有一行且一列,可以使用简单类型进行输出映射。
1.2 输出pojo对象和pojo列表
不管是输出的pojo单个对象还是一个列表(list中包括pojo),在mapper.xml中resultType指定的类型是一样的。
在mapper.java指定的方法返回值类型不一样:
1.2.1 输出单个pojo对象,方法返回值是单个对象类型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z6ZKQkVr-1641215111326)(image/wps24.jpg)]
1.2.2 输出pojo对象list,方法返回值是List<Pojo>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tiaEpQBF-1641215111327)(image/wps25.jpg)]
生成的动态代理对象中是根据mapper.java中的方法的返回值类型确定是调用selectOne(返回单个对象调用)还是selectList (返回集合对象调用 ).
2.resultMap
mybatis中使用resultMap完成高级输出结果映射。
2.1 resultMap使用方法
如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间作一个映射关系。
1、定义resultMap
2、使用resultMap作为statement的输出映射类型
2.2 将下边的sql使用User完成映射
SELECT id a , username b FROM USER WHERE id=#{value} User类中属性名和上边查询列名不一致。
2.2.1定义resultMap
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0yTObHD6-1641215111327)(image/wps26.jpg)]
2.2.2 使用resultMap作为statement的输出映射类型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-61qb2TlH-1641215111327)(image/wps27.jpg)]
2.2.3 mapper.java
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pjp4nTgM-1641215111328)(image/wps28.jpg)]
2.2.4 测试
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vU4nDi4Z-1641215111330)(image/wps29.jpg)]
3. 小结
使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间作一个映射关系。
七.动态sql
1.什么是动态sql?
mybatis核心对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接、组装。
2.什么是sql片段?
将实现的动态sql的代码块抽取出来,组成一个sql片段。其它的statement中就可以引用sql片段,方便程序员进行开发。
3.需求
1.需求:通过用户性别和姓名查询用户列表 PS:不允许性别或者姓名为null或者空串
2.需求:通过用户性别和姓名查询用户列表条数 PS:不允许性别或者姓名为null或者空串
3.需求:通过用户性别和姓名查询用户列表,且id值是15或20或25 PS:不允许性别或者姓名为null或者空串
4.编写UserCustom类
public class UserCustom extends User{
}
5.编写UserQueryVO类
public class UserQueryVO {
private UserCustom userCustom;
private List<Integer> ids;
public UserCustom getUserCustom() {
return userCustom;
}
public void setUserCustom(UserCustom userCustom) {
this.userCustom = userCustom;
}
public List<Integer> getIds() {
return ids;
}
public void setIds(List<Integer> ids) {
this.ids = ids;
}
}
6.编写UserMapper.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.cm.ch02.sql.UserMapper">
<sql id="user_query">
<if test="userCustom!=null">
<if test="userCustom.sex!=null and userCustom.sex!=''">
and sex = #{userCustom.sex}
</if>
<if test="userCustom.username!=null and userCustom.username!=''">
and username like concat('%',#{userCustom.username},'%')
</if>
</if>
</sql>
<sql id="user_query_id">
<if test="ids!=null">
<foreach collection="ids" item="user_id" open="and (" close=")" separator="or">
id=#{user_id}
</foreach>
</if>
</sql>
<select id="selectList" parameterType="UserQueryVO" resultType="UserCustom">
select * from user
<where>
<include refid="user_query"></include>
</where>
</select>
<select id="selectCount" parameterType="UserQueryVO" resultType="int">
select count(*) from user
<where>
<include refid="user_query"></include>
</where>
</select>
<select id="selectByIds" parameterType="UserQueryVO" resultType="UserCustom">
select * from user
<where>
<include refid="user_query"></include>
<include refid="user_query_id"></include>
</where>
</select>
</mapper>
7.编写UserMapper.java接口
import com.cm.entity.UserCustom;
import com.cm.entity.UserQueryVO;
import java.util.List;
public interface UserMapper {
public List<UserCustom> selectList(UserQueryVO vo);
public int selectCount(UserQueryVO vo);
public List<UserCustom> selectByIds(UserQueryVO vo);
}
8.在核心配置文件中添加扫描
<mappers>
<package name="com.cm.ch02.sql" />
</mappers>
9.测试
public class UserMapperTest {
private SqlSessionFactory factory;
@Before
public void setUp() throws Exception {
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
factory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void selectList() {
SqlSession sqlSession = factory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
UserCustom userCustom = new UserCustom();
userCustom.setSex("1");
userCustom.setUsername("明");
UserQueryVO vo = new UserQueryVO();
vo.setUserCustom(userCustom);
List<UserCustom> list = userMapper.selectList(vo);
for (UserCustom user: list) {
System.out.println(user);
}
sqlSession.close();
}
@Test
public void selectCount() {
SqlSession sqlSession = factory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
UserCustom userCustom = new UserCustom();
userCustom.setSex("1");
userCustom.setUsername(null);
UserQueryVO vo = new UserQueryVO();
vo.setUserCustom(userCustom);
int count = userMapper.selectCount(vo);
System.out.println(count);
sqlSession.close();
}
@Test
public void selectByIds() {
SqlSession sqlSession = factory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
UserCustom userCustom = new UserCustom();
userCustom.setSex("");
userCustom.setUsername("明");
List<Integer> ids = new ArrayList<>();
ids.add(15);
ids.add(20);
ids.add(25);
UserQueryVO vo = new UserQueryVO();
vo.setUserCustom(userCustom);
vo.setIds(ids);
List<UserCustom> list = userMapper.selectByIds(vo);
for (UserCustom user: list) {
System.out.println(user);
}
sqlSession.close();
}
}
八.高级映射
1.分析订单商品数据模型
1.1 每张表记录的数据内容
分模块对每张表记录的内容进行熟悉,相当于你学习系统需求(功能)的过程。
用户表:user
? 记录了购买商品的用户信息
订单表:orders
? 记录了用户所创建的订单(购买商品的订单)
订单明细表:orderdetail
? 记录了订单的详细信息即购买商品的信息
商品表:items
? 记录了商品信息
1.2 每张表重要的字段设置
非空字段、外键字段
1.3 数据库级别表与表之间的关系
外键关系:
1).外键user_id所在的表orders叫做子表;通过外键user_id指向主表(父表)user中的id
2).外键orders_id所在的表orderdetail叫做子表;通过外键orders_id指向主表(父表)orders中的id
3).外键items_id所在的表orderdetail叫做子表;通过外键items_id指向主表(父表)items中的id
1.4 表与表之间的业务关系
在分析表与表之间的业务关系时一定要建立在某个业务意义基础上去分析。
1).先分析数据库级别之间,有关系的表之间的业务关系:
user和orders:
user ---->orders:一个用户可以创建多个订单,一对多
orders --->user:一个订单只由一个用户创建,一对一
orders和orderdetail:
orders --->orderdetail:一个订单可以包括多个订单明细,因为一个订单可以购买多个商品,每个商品的购买信息在orderdetail记录,一对多关系
orderdetail ---> orders:一个订单明细只能包括在一个订单中,一对一
orderdetail和items:
orderdetail --->items:一个订单明细只对应一个商品信息,一对一
items ---> orderdetail:一个商品可以包括在多个订单明细 ,一对多
2).再分析数据库级别之间,没有关系的表之间是否有业务关系:
orders和items:
orders和items之间可以通过orderdetail表建立关系。
1.5 画图分析
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NQP0J6L6-1641215111331)(image/image-20200714004659822.png)]
2.高级映射-一对一查询
2.1 需求
查询订单信息,关联查询创建订单的用户信息
2.2 sql语句
select orders.*,user.sex,user.address,user.username,user.birthday
from orders,user
where orders.user_id = user.id
2.3 使用resultMap映射的思路
使用resultMap将查询结果中的订单信息映射到Orders对象中,在orders类中添加User属性,将关联查询出来的用户信息映射到orders对象中的user属性中。
2.4 新建Orders类
import java.util.Date;
public class Orders {
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
public Orders(Integer id, Integer userId, String number, Date createtime, String note) {
super();
this.id = id;
this.userId = userId;
this.number = number;
this.createtime = createtime;
this.note = note;
}
public Orders() {
super();
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number == null ? null : number.trim();
}
public Date getCreatetime() {
return createtime;
}
public void setCreatetime(Date createtime) {
this.createtime = createtime;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note == null ? null : note.trim();
}
@Override
public String toString() {
return "Orders [id=" + id + ", userId=" + userId + ", number=" + number + ", createtime=" + createtime
+ ", note=" + note + "]";
}
}
2.5 新建OrdersCustom类
public class OrdersCustom extends Orders{
private UserCustom userCustom;
public UserCustom getUserCustom() {
return userCustom;
}
public void setUserCustom(UserCustom userCustom) {
this.userCustom = userCustom;
}
@Override
public String toString() {
return super.toString()+"OrdersCustom [userCustom=" + userCustom + "]";
}
}
2.6 创建OrdersUserMapper.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.cm.ch03.oo.OrdersUserMapper">
<resultMap type="OrdersCustom" id="orderUserResultMap">
<id column="id" property="id" />
<result column="user_id" property="userId"/>
<result column="number" property="number"/>
<result column="createtime" property="createtime"/>
<result column="note" property="note"/>
<association property="userCustom" javaType="UserCustom">
<id column="user_id" property="id" />
<result column="username" property="username"/>
<result column="birthday" property="birthday"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/>
</association>
</resultMap>
<select id="selectOrderUserResultMap" resultMap="orderUserResultMap">
select orders.*,user.sex,user.address,user.username,user.birthday
from orders,user
where orders.user_id = user.id
</select>
</mapper>
2.7 创建OrdersUserMapper.java接口
import com.cm.entity.OrdersCustom;
import java.util.List;
public interface OrdersUserMapper {
public List<OrdersCustom> selectOrderUserResultMap();
}
2.8 在核心配置文件中添加扫描
<mappers>
<package name="com.cm.ch03.oo" />
</mappers>
2.9 测试类
import java.util.List;
public class OrdersUserMapperTest {
private SqlSessionFactory factory;
@Before
public void setUp() throws Exception {
factory = new SqlSessionFactoryBuilder().build(
Resources.getResourceAsStream("sqlMapConfig.xml"));
}
@Test
public void testSelectOrderUserResultMap(){
SqlSession sqlSession = factory.openSession();
OrdersUserMapper mapper = sqlSession.getMapper(OrdersUserMapper.class);
List<OrdersCustom> list = mapper.selectOrderUserResultMap();
for (OrdersCustom ordersCustom : list) {
System.out.println(ordersCustom);
}
sqlSession.close();
}
}
3.高级映射-一对多查询
3.1 需求
查询订单及订单明细的信息
3.2 sql语句
select orders.*,
orderdetail.id od_id ,
orderdetail.items_id,
orderdetail.items_num
from orders,orderdetail
where orders.id = orderdetail.orders_id
3.3 新建订单详情OrderDetail类
public class OrderDetail {
private Integer id;
private Integer orderId;
private Integer itemId;
private Integer itemNum;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getOrderId() {
return orderId;
}
public void setOrderId(Integer orderId) {
this.orderId = orderId;
}
public Integer getItemId() {
return itemId;
}
public void setItemId(Integer itemId) {
this.itemId = itemId;
}
public Integer getItemNum() {
return itemNum;
}
public void setItemNum(Integer itemNum) {
this.itemNum = itemNum;
}
public OrderDetail() {
super();
}
public OrderDetail(Integer id, Integer orderId, Integer itemId, Integer itemNum) {
super();
this.id = id;
this.orderId = orderId;
this.itemId = itemId;
this.itemNum = itemNum;
}
@Override
public String toString() {
return "OrderDetail [id=" + id + ", orderId=" + orderId + ", itemId=" + itemId + ", itemNum=" + itemNum + "]";
}
}
3.4 新建OrderDetailCustom订单详情拓展类
public class OrderDetailCustom extends OrderDetail{
}
3.5 修改OrdersCustom类
public class OrdersCustom extends Orders{
private UserCustom userCustom;
private List<OrderDetailCustom> detailCustomList;
public UserCustom getUserCustom() {
return userCustom;
}
public void setUserCustom(UserCustom userCustom) {
this.userCustom = userCustom;
}
public List<OrderDetailCustom> getDetailCustomList() {
return detailCustomList;
}
public void setDetailCustomList(List<OrderDetailCustom> detailCustomList) {
this.detailCustomList = detailCustomList;
}
@Override
public String toString() {
return super.toString()+"OrdersCustom{" +
"userCustom=" + userCustom +
", detailCustomList=" + detailCustomList +
'}';
}
}
3.6 创建OrderAndOrderDetailMapper.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.cm.ch04.om.OrderAndOrderDetailMapper">
<resultMap type="OrdersCustom" id="OrdersAndOrderDetailResultMap">
<id column="id" property="id"/>
<result column="user_id" property="userId" />
<result column="number" property="number" />
<result column="createtime" property="createtime" />
<result column="note" property="note" />
<collection property="detailCustomList" ofType="OrderDetailCustom">
<id column="od_id" property="id"/>
<result column="id" property="orderId"/>
<result column="items_id" property="itemId"/>
<result column="items_num" property="itemNum"/>
</collection>
</resultMap>
<select id="selectOrderAndOrderDetail" resultMap="OrdersAndOrderDetailResultMap">
select orders.*,
orderdetail.id od_id ,
orderdetail.items_id,
orderdetail.items_num
from orders,orderdetail
where orders.id = orderdetail.orders_id
</select>
<resultMap type="OrdersCustom" id="result" extends="OrdersAndOrderDetailResultMap">
<association property="userCustom" javaType="UserCustom">
<id column="user_id" property="id"/>
<result column="username" property="username"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
<result column="address" property="address"/>
</association>
</resultMap>
<select id="selectOrderANDOrderDetailUser" resultMap="result">
select orders.*,
orderdetail.id od_id ,
orderdetail.items_id,
orderdetail.items_num,
user.sex,
user.username,
user.address,
user.birthday
from orders,orderdetail,user
where orders.id = orderdetail.orders_id and orders.user_id = user.id
</select>
</mapper>
3.7 创建OrderAndOrderDetailMapper.java接口
import java.util.List;
public interface OrderAndOrderDetailMapper {
public List<OrdersCustom> selectOrderAndOrderDetail();
public List<OrdersCustom> selectOrderANDOrderDetailUser();
}
3.8 在核心配置文件中添加扫描
<mappers>
<package name="com.cm.ch04.om" />
</mappers>
3.9 测试类
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.Before;
import org.junit.Test;
import java.util.List;
public class OrderAndOrderDetailMapperTest {
private SqlSessionFactory factory;
@Before
public void setUp() throws Exception {
factory = new SqlSessionFactoryBuilder().build(
Resources.getResourceAsStream("sqlMapConfig.xml"));
}
@Test
public void testSelectOrderAndOrderDetail() {
SqlSession sqlSession = factory.openSession();
OrderAndOrderDetailMapper mapper = sqlSession.getMapper(OrderAndOrderDetailMapper.class);
List<OrdersCustom> list = mapper.selectOrderAndOrderDetail();
for (OrdersCustom ordersCustom : list) {
System.out.println(ordersCustom);
}
System.out.println(list.size());
sqlSession.close();
}
@Test
public void testSelectOrderANDOrderDetailUser(){
SqlSession sqlSession = factory.openSession();
OrderAndOrderDetailMapper mapper = sqlSession.getMapper(OrderAndOrderDetailMapper.class);
List<OrdersCustom> list = mapper.selectOrderANDOrderDetailUser();
for (OrdersCustom ordersCustom : list) {
System.out.println(ordersCustom);
}
System.out.println(list.size());
sqlSession.close();
}
}
4.高级映射-多对多查询
4.1 需求
查询用户及用户购买商品信息
4.2 sql语句
select u.*,
o.id oid, o.number, o.createtime ,
d.id did, d.items_num,
i.id iid, i.name, i.createtime itemsTime ,i.detail,i.price
from user u,orders o,orderdetail d,items i
where u.id = o.user_id and o.id = d.orders_id and d.items_id = i.id
4.3 新建商品Items类
import java.util.Date;
public class Items {
private Integer id;
private String name;
private Float price;
private String detail;
private String pic;
private Date createtime;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Float getPrice() {
return price;
}
public void setPrice(Float price) {
this.price = price;
}
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail;
}
public String getPic() {
return pic;
}
public void setPic(String pic) {
this.pic = pic;
}
public Date getCreatetime() {
return createtime;
}
public void setCreatetime(Date createtime) {
this.createtime = createtime;
}
public Items() {
super();
}
public Items(Integer id, String name, Float price, String detail, String pic, Date createtime) {
super();
this.id = id;
this.name = name;
this.price = price;
this.detail = detail;
this.pic = pic;
this.createtime = createtime;
}
@Override
public String toString() {
return "Items [id=" + id + ", name=" + name + ", price=" + price + ", detail=" + detail + ", pic=" + pic
+ ", createtime=" + createtime + "]";
}
}
4.4 新建ItemsCustom商品拓展类
public class ItemsCustom extends Items{
}
4.5 修改OrderDetailCustom订单详情拓展类
public class OrderDetailCustom extends OrderDetail{
private ItemsCustom itemsCustom;
public ItemsCustom getItemsCustom() {
return itemsCustom;
}
public void setItemsCustom(ItemsCustom itemsCustom) {
this.itemsCustom = itemsCustom;
}
}
4.6 修改UserCustom用户拓展类
public class UserCustom extends User{
private List<OrdersCustom> ordersList;
public List<OrdersCustom> getOrdersList() {
return ordersList;
}
public void setOrdersList(List<OrdersCustom> ordersList) {
this.ordersList = ordersList;
}
@Override
public String toString() {
return "UserCustom [toString()=" + super.toString() + "]";
}
}
4.7 创建UserItemsMapper.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.cm.ch05.mm.UserItemsMapper">
<resultMap type="UserCustom" id="map">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="birthday" property="birthday"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/>
<collection property="ordersList" ofType="OrdersCustom">
<id column="oid" property="id"/>
<result column="id" property="userId"/>
<result column="number" property="number"/>
<result column="createtime" property="createtime"/>
<collection property="detailCustomList" ofType="OrderDetailCustom">
<id column="did" property="id"/>
<result column="oid" property="orderId"/>
<result column="iid" property="itemId"/>
<result column="items_num" property="itemNum"/>
<association property="itemsCustom" javaType="ItemsCustom">
<id column="iid" property="id"/>
<result column="name" property="name"/>
<result column="itemsTime" property="createtime"/>
<result column="detail" property="detail"/>
<result column="price" property="price"/>
</association>
</collection>
</collection>
</resultMap>
<select id="selectUserItems" resultMap="map">
select u.*,
o.id oid, o.number, o.createtime ,
d.id did, d.items_num,
i.id iid, i.name, i.createtime itemsTime ,i.detail,i.price
from user u,orders o,orderdetail d,items i
where u.id = o.user_id and o.id = d.orders_id and d.items_id = i.id
</select>
</mapper>
4.8 创建UserItemsMapper接口
import java.util.List;
public interface UserItemsMapper {
public List<UserCustom> selectUserItems();
}
4.9 在核心配置文件中添加扫描
<mappers>
<package name="com.cm.ch05.mm" />
</mappers>
4.10 测试类
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.Before;
import org.junit.Test;
import java.util.List;
public class UserItemsMapperTest {
private SqlSessionFactory factory;
@Before
public void setUp() throws Exception {
factory = new SqlSessionFactoryBuilder().build(
Resources.getResourceAsStream("sqlMapConfig.xml"));
}
@Test
public void testSelectUserItems() {
SqlSession sqlSession = factory.openSession();
UserItemsMapper mapper = sqlSession.getMapper(UserItemsMapper.class);
List<UserCustom> list = mapper.selectUserItems();
for (UserCustom userCustom : list) {
System.out.println("用户号:"+userCustom.getId()+" 用户名: "+userCustom.getUsername());
for(OrdersCustom ordersCustom : userCustom.getOrdersList()){
System.out.println("订单号:"+ordersCustom.getId() +" 用户号:"+ordersCustom.getUserId());
System.out.println("=============");
for(OrderDetailCustom od:ordersCustom.getDetailCustomList()){
System.out.println("订单详情号:"+od.getId()+" 订单号:"+od.getOrderId()+" 商品号:"+od.getItemId());
ItemsCustom item = od.getItemsCustom();
System.out.println("商品号:"+item.getId()+" 商品名称:"+item.getName());
}
}
}
sqlSession.close();
}
}
5.高级映射-延迟加载
1.什么是延迟加载
resultMap可以实现高级映射(使用association、collection实现一对一及一对多映射),association、collection具备延迟加载功能。
需求:如果查询订单并且关联查询用户信息。
如果先查询订单信息即可满足要求,当我们需要查询用户信息时再查询用户信息。把对用户信息的按需去查询就是延迟加载。
延迟加载:先从单表查询、需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。
2.使用association实现延迟加载
2.1 需求
查询订单并且关联查询用户信息
2.2 mapper.xml
需要定义两个mapper的方法对应的statement。
1、只查询订单信息
SELECT * FROM orders
在查询订单的statement中使用association去延迟加载(执行)下边的satatement(关联查询用户信息)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hvhXcZbV-1641215111332)(image/wps31.jpg)]
2、关联查询用户信息
? 通过上边查询到的订单信息中user_id去关联查询用户信息
? 使用UserMapper.xml中的findUserById
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0R4g7HqT-1641215111333)(image/wps32.jpg)]
上边先去执行selectOrderUserLazyloading,当需要去查询用户的时候再去执行findUserById,通过resultMap的定义将延迟加载执行配置起来。
2.3 延迟加载resultMap
使用association中的select指定延迟加载去执行的statement的id。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CnNscYWP-1641215111333)(image/wps33.jpg)]
2.4 mapper.java
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FJ49jpY3-1641215111333)(image/wps34.jpg)]
2.5 测试
2.5.1 测试思路
1、执行上边mapper方法(selectOrderUserLazyloading),内部去调用com.mybatis.ch21.lazyloading.OrderUserMapper中的selectOrderUserLazyloading,只查询orders信息(单表)。
2、在程序中去遍历上一步骤查询出的List,当我们调用Orders中的getUser方法时,开始进行延迟加载。
3、延迟加载,去调用UserMapper.xml中findUserById这个方法获取用户信息。
2.5.2 延迟加载配置
mybatis默认没有开启延迟加载,需要在SqlMapConfig.xml中setting配置。
在mybatis核心配置文件中配置: lazyLoadingEnabled、aggressiveLazyLoading
设置项 | 描述 | 允许值 | 默认值 |
---|
lazyLoadingEnabled | 全局性设置懒加载。如果设为‘false’,则所有相关联的都会被初始化加载。 | true | false | false | aggressiveLazyLoading | 当设置为‘true’的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载。 | true | false | true | lazyLoadTriggerMethods | 指定触发延迟加载的对象的方法。 | A method name list separated by commas | equals,clone, hashCode,toString |
在SqlMapConfig.xml中配置:
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
<setting name="lazyLoadTriggerMethods" value=""/>
</settings>
2.5.3 测试代码
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AyEwIHRF-1641215111334)(image/wps35.jpg)]
3.延迟加载思考
不使用mybatis提供的association及collection中的延迟加载功能,如何实现延迟加载??
实现方法如下:
定义两个mapper方法:
1、查询订单列表
2、根据用户id查询用户信息
实现思路:
先去查询第一个mapper方法,获取订单信息列表
在程序中(service),按需去调用第二个mapper方法去查询用户信息。
总之:
使用延迟加载方法,先去查询简单的sql(最好单表,也可以关联查询),再去按需要加载关联查询的其它信息。
九.查询缓存
1.一级缓存
1.1 什么是查询缓存
mybatis提供查询缓存,用于减轻数据压力,提高数据库性能。
mybaits提供一级缓存,和二级缓存。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lToEbQ6A-1641215111334)(image/wps41.jpg)]
**一级缓存是SqlSession级别的缓存。**在操作数据库时需要构造 sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。
二级缓存是mapper映射文件级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
为什么要用缓存?
如果缓存中有数据就不用从数据库中获取,大大提高系统性能。
1.2 一级缓存
1.2.1 一级缓存工作原理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8F1CdZkN-1641215111335)(image/wps42.jpg)]
第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户信息。得到用户信息后,将用户信息存储到一级缓存中。
如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。
1.2.2 一级缓存测试
mybatis默认支持一级缓存,不需要在配置文件去配置。
按照上边一级缓存原理步骤去测试。
UserMapper.xml
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p8hcwcp7-1641215111335)(image/wps43.jpg)]
UserMapper.java
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lHsDg6Pu-1641215111336)(image/wps44.jpg)]
测试类:UserMapperTest.java
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P4D1H65j-1641215111336)(image/wps45.jpg)]
1.2.3 一级缓存应用
正式开发,是将mybatis和spring进行整合开发,事务控制在service中。
一个service方法中包括很多mapper方法调用。
service{
}
service{
}
如果是执行两次service调用查询相同的用户信息,不走一级缓存,因为service方法结束,sqlSession就关闭,一级缓存就清空。
2.二级缓存
2.1 原理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ps6hepL3-1641215111336)(image/wps51.jpg)]
首先开启mybatis的二级缓存。
sqlSession1去查询用户id为1的用户信息,查询到用户信息会将查询数据存储到二级缓存中。
如果SqlSession3去执行相同 mapper下sql,执行commit提交,清空该 mapper下的二级缓存区域的数据。
sqlSession2去查询用户id为1的用户信息,去缓存中找是否存在数据,如果存在直接从缓存中取出数据。
二级缓存与一级缓存区别,二级缓存的范围更大,多个sqlSession可以共享一个UserMapper的二级缓存区域。
UserMapper有一个二级缓存区域(按namespace分),其它mapper也有自己的二级缓存区域(按namespace分)。
每一个namespace的mapper都有一个二缓存区域,两个mapper的namespace如果相同,这两个mapper执行sql查询到数据将存在相同的二级缓存区域中。
2.2 开启二级缓存
mybaits的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,还要在具体的mapper.xml中开启二级缓存。
第一步:在核心配置文件SqlMapConfig.xml中加入
<setting name="cacheEnabled" value="true"/>
| 描述 | 允许值 | 默认值 |
---|
cacheEnabled | 对在此配置文件下的所有cache 进行全局性开/关设置。 | true false | true |
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uLtJ21mR-1641215111337)(image/wps52.jpg)]
第二步:在UserMapper.xml中开启二缓存
UserMapper.xml下的sql执行完成会存储到它的缓存区域(HashMap)。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f2uxme85-1641215111337)(image/wps53.jpg)]
2.3 调用pojo类实现序列化接口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RbM4lpwl-1641215111337)(image/wps54.jpg)]
为了将缓存数据取出执行反序列化操作,因为二级缓存数据存储介质多种多样,不一样在内存。
2.4 测试方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y9nQF1MS-1641215111338)(image/wps55.jpg)]
2.5 useCache 配置
在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存。
<select id="findUserById" parameterType="int" resultType="user" useCache="false">
总结:针对每次查询都需要最新的数据sql,要设置成useCache=false,禁用二级缓存。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-svuW6X4t-1641215111338)(image/wps56.jpg)]
2.6 刷新缓存(清空缓存)
在mapper的同一个namespace中,如果有其它insert、update、delete操作数据后需要刷新缓存,如果不执行刷新缓存会出现脏读。
设置statement配置中的flushCache=“true” 属性,默认情况下为true即刷新缓存,如果改成false则不会刷新。使用缓存时如果手动修改数据库表中的查询数据会出现脏读。
如下:
<insert id="insertUser" parameterType=" User" flushCache="true">
总结:一般下执行完commit操作都需要刷新缓存,flushCache=true表示刷新缓存,这样可以避免数据库脏读。
2.7 二级应用场景
对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访问速度,业务场景比如:耗时较高的统计分析sql、电话账单查询sql等。
实现方法如下:通过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushInterval,比如设置为30分钟、60分钟、24小时等,根据需求而定。
2.8 二级缓存局限性
? mybatis二级缓存对细粒度的数据级别的缓存实现不好,比如如下需求:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品信息,此时如果使用mybatis的二级缓存就无法实现当一个商品变化时只刷新该商品的缓存信息而不刷新其它商品的信息,因为mybaits的二级缓存区域以mapper为单位划分,当一个商品信息变化会将所有商品信息的缓存数据全部清空。解决此类问题需要在业务层根据需求对数据有针对性缓存。
十.mybatis和spring整合
1.概念
Spring
Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。 简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
MyBatis
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。MyBatis是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAO)MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
2.整合思路
需要Spring通过IOC方式管理SqlSessionFactory。 spring和mybatis整合生成代理对象,使用SqlSessionFactory创建SqlSession.(Sping和mybati整合自动完成)。 持久层的mapper都交由有spring进行管理。
3.准备工作
3.1 创建一个新的Maven的java工程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O39YDZQB-1641215111338)(image/image-20210304200206857.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YQEaNcRa-1641215111339)(image/image-20210304200316460.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C9FaJyVX-1641215111339)(image/image-20210304200506823.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ypkQnQFW-1641215111340)(image/image-20210304200542827.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1oVANOZf-1641215111340)(image/image-20210304200615366.png)]
3.2 新建属性文件
创建resources文件夹,右击选择Mark Directory as 为Resources root
新建db.properties文件
#mysql
db.username = root
db.password = root
db.jdbcUrl = jdbc:mysql://localhost:3306/testmybatis?useUnicode=true&characterEncoding=utf8
db.driverClass = com.mysql.jdbc.Driver
新建log4j.properties文件
# Global logging configuration
# 在开发环境下日志级别要设置成DEBUG,生产环境设置成info或error
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
3.3 引入相关依赖
Maven引入需要的依赖
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>5.3.4</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.7.0</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.5</version>
</dependency>
</dependencies>
4.整合Spring和MyBatis XML+注解版
4.1 新建MyBatis核心配置文件
在resources文件夹下新建SqlMapConfig.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>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<typeAliases>
<package name="com.igeek.ssm.pojo"/>
</typeAliases>
</configuration>
4.2 新建Spring的配置文件
在resources文件夹下,新建applicationContext.xml文件
4.2.1 配置数据源
在applicationContext.xml配置数据源、加载外部属性文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:property-placeholder location="db.properties"></context:property-placeholder>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${db.username}"></property>
<property name="password" value="${db.password}"></property>
<property name="jdbcUrl" value="${db.jdbcUrl}"></property>
<property name="driverClass" value="${db.driverClass}"></property>
</bean>
</beans>
4.2.2 配置SqlSessionFactory
在applicationContext.xml配置会话工厂实例
<bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="mybatis/SqlMapConfig.xml"></property>
<property name="dataSource" ref="dataSource"></property>
</bean>
注意:
1.使用IDEA的maven工具进行开发时,会出现spring代理器无法读取mapper配置文件 XXXMaper.xml的问题—— org.apache.ibatis.binding.BindingException,可以在pom.xml中配置下面这句话:
...
<build>
<resources>
<resource>
<directory>${basedir}/src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>${basedir}/src/main/resources</directory>
</resource>
</resources>
</build>
...
2.若没有添加上述配置,则需要将XxxMapper.xml文件建在resources文件夹下,并在配置SqlSessionFactory时需添加下方属性:
<property name="mapperLocations">
<list>
<value>classpath:/mapper/*Mapper.xml</value>
</list>
</property>
4.2.3 配置Mapper扫描包
在applicationContext.xml配置Mapper扫描器
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.igeek.ssm.mapper"></property>
<property name="sqlSessionFactoryBeanName" value="factory"></property>
</bean>
4.2.4 配置事务
在applicationContext.xml配置事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
4.3 测试
4.3.1 创建User类
public class User{
private int id;
private String name;
private String gender;
private Date birthday;
private int age;
private String pic;
private String pwd;
private String state;
...
}
4.3.2 创建UserMapper接口与UserMapper.xml映射文件
public interface UserMapper {
public User findUserById(int id);
public void updateUser(User user);
}
<?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.igeek.ssm.mapper.UserMapper">
<select id="findUserById" parameterType="int" resultType="User">
select * from user where id = #{id}
</select>
<update id="updateUser" parameterType="User">
update user set name=#{name},gender=#{gender},age=#{age} where id=#{id}
</update>
</mapper>
4.3.3 创建UserService业务逻辑类
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Transactional(readOnly = true)
public User findUserById(int id){
return userMapper.findUserById(id);
}
@Transactional
public void updateUser(int id){
User user = userMapper.findUserById(id);
user.setName("aaa");
user.setAge(18);
userMapper.updateUser(user);
user.setName("bbb");
user.setAge(20);
userMapper.updateUser(user);
}
}
4.3.4 创建UserServiceTest测试类
@SpringJUnitConfig(locations = "classpath:applicationContext.xml")
class UserServiceTest {
@Autowired(required = false)
private UserService userService;
@Test
void findUserById() {
User user = userService.findUserById(1);
System.out.println(user);
}
@Test
void updateUser() {
userService.updateUser(1);
}
}
5.整合Spring和MyBatis JavaConfig+注解版
5.1 在配置类中添加MyBatis的配置
MyBatisConfig.java
package com.igeek.ssm.config;
import org.apache.ibatis.session.Configuration;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
import java.io.IOException;
import java.util.HashSet;
@org.springframework.context.annotation.Configuration
@MapperScan(basePackages = "com.igeek.ssm.mapper")
@Import(MySpringConfig.class)
public class MyBatisConfig {
@Bean
public SqlSessionFactoryBean factory(DataSource dataSource) throws IOException {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setTypeAliasesPackage("com.igeek.ssm.pojo");
Configuration configuration = new Configuration();
configuration.setMapUnderscoreToCamelCase(true);
configuration.setLazyLoadingEnabled(true);
configuration.setAggressiveLazyLoading(false);
configuration.setLazyLoadTriggerMethods(new HashSet<>());
configuration.setCacheEnabled(true);
factory.setConfiguration(configuration);
factory.setMapperLocations(
new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/*.xml"));
return factory;
}
}
5.2 在配置类中添加Spring的配置
MySpringConfig.java
package com.igeek.ssm.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
@Configuration
@ComponentScan(basePackages = "com.igeek.ssm")
@PropertySource(value = "db.properties")
@EnableTransactionManagement
public class MySpringConfig {
@Bean(destroyMethod = "")
public ComboPooledDataSource dataSource(
@Value("${db.username}") String user,
@Value("${db.password}") String password,
@Value("${db.jdbcUrl}") String jdbcUrl,
@Value("${db.driverClass}") String driverClass
) throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(password);
dataSource.setJdbcUrl(jdbcUrl);
dataSource.setDriverClass(driverClass);
return dataSource;
}
@Bean
public DataSourceTransactionManager transactionManager(DataSource dataSource){
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
return transactionManager;
}
}
5.3 创建Orders类
public class Orders {
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
...
}
5.4 创建OrdersMapper接口和OrdersMapper.xml映射文件
public interface OrdersMapper {
public List<Orders> findOrders();
public void updateOrders(Orders orders);
}
在resources文件夹下,mapper文件夹中创建OrdersMapper.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.igeek.ssm.mapper.OrdersMapper">
<select id="findOrders" resultType="Orders">
select * from orders
</select>
<update id="updateOrders" parameterType="Orders">
update orders set number=#{number} where id=#{id}
</update>
</mapper>
5.5 创建OrderService类
@Service
public class OrderService {
@Autowired
private OrdersMapper ordersMapper;
@Transactional(readOnly = true)
public List<Orders> findAllOrders(){
return ordersMapper.findOrders();
}
@Transactional
public void updateOrders(){
Orders orders1 = new Orders();
orders1.setId(3);
orders1.setNumber(UUID.randomUUID().toString().replaceAll("-",""));
ordersMapper.updateOrders(orders1);
Orders orders2 = new Orders();
orders2.setId(4);
orders2.setNumber(UUID.randomUUID().toString().replaceAll("-",""));
ordersMapper.updateOrders(orders2);
}
}
5.6 创建OrderServiceTest测试类
import com.igeek.ssm.config.MyBatisConfig;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
@SpringJUnitConfig(classes = MyBatisConfig.class)
class OrderServiceTest {
@Autowired(required = false)
private OrderService orderService;
@Test
void findAllOrders() {
System.out.println(orderService.findAllOrders());
System.out.println(orderService.findAllOrders().size());
}
@Test
void updateOrders() {
orderService.updateOrders();
}
}
十一.逆向工程
1.什么是逆向工程?
? mybaits需要程序员自己编写sql语句,mybatis官方提供逆向工程可以针对单表自动生成mybatis执行所需要的代码(mapper.java,mapper.xml、pojo…)企业实际开发中,常用的逆向工程方式:由数据库的表生成java代码。
2.使用逆向工程
2.1 修改pom.xml
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.5</version>
</dependency>
2.2 在pom.xml中新建mybatis-generator插件,在plugins标签内添加
注意:这里我们的generatorConfig.xml文件需要正确的路径,前面的${basedir}自动匹配当前路径,不用修改
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.1</version>
<configuration>
<configurationFile>${basedir}/src/resources/generatorConfig.xml</configurationFile>
<overwrite>true</overwrite>
<verbose>true</verbose>
</configuration>
</plugin>
2.3 在src/resources下,创建generatorConfig.xml文件
注意:文件中的路径都是绝对路径
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<classPathEntry location="E:\5.JSP+Servlet\project\repo\mysql\mysql-connector-java\5.1.38\mysql-connector-java-5.1.38.jar"/>
<context id="testTables" targetRuntime="MyBatis3">
<commentGenerator>
<property name="suppressAllComments" value="true" />
</commentGenerator>
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/testmybatis"
userId="root"
password="root">
<property name="nullCatalogMeansCurrent" value="true"/>
</jdbcConnection>
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<javaModelGenerator targetPackage="com.igeek.ssm.pojo"
targetProject=".\src\main\java">
<property name="enableSubPackages" value="false" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<sqlMapGenerator targetPackage="com.igeek.ssm.mapper"
targetProject=".\src\main\java">
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.igeek.ssm.mapper"
targetProject=".\src\main\java">
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<table tableName="user"></table>
<table tableName="orders"></table>
<table tableName="orderdetail"></table>
<table tableName="items"></table>
</context>
</generatorConfiguration>
注意:
? 在 MySQL 8.0 以上的版本中,在生成 User 表的实体类时,Mybatis Generator 会找到多张 User 表,包括 MySQL information schemas 中的多张 User 表,生成了多个 User 相关的实体类。 ? 若要保证只生成自己指定的 database 中的 User 表,首先要在 中的 connectionURL 中指定数据库的实例名,然后在 中添加相关配置信息,即
,即可保证只生成自己需要的 User 类。
2.4 配置maven的启动配置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eWq3imz4-1641215111341)(image/image-20200714022927793.png)]
编辑配置,添加maven,命令行添加 mybatis-generator:generate -e
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HgizsBrM-1641215111341)(image/image-20200714023238566.png)]
2.5 点击运行按钮即可
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BJGUAm5o-1641215111341)(image/image-20210304203003209.png)]
将会生成com.igeek.ssm.pojo、com.igeek.ssm.mapper包,及pojo类、mapper.java、mapper.xml文件。
2.6 需求:根据商品名称模糊查询信息
测试类
import com.igeek.ssm.pojo.Items;
import com.igeek.ssm.pojo.ItemsExample;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import java.util.List;
@SpringJUnitConfig(locations = "classpath:spring/applicationContext.xml")
class ItemsMapperTest {
@Autowired
private ItemsMapper itemsMapper;
@Test
void selectByExample() {
ItemsExample itemsExample = new ItemsExample();
ItemsExample.Criteria criteria = itemsExample.createCriteria();
criteria.andNameLike("%机%");
List<Items> itemsList = itemsMapper.selectByExample(itemsExample);
for (Items items : itemsList) {
System.out.println(items.getName()+" : "+items.getDetail());
}
}
@Test
void updateByExampleWithBLOBs() {
Items items = itemsMapper.selectByPrimaryKey(1);
System.out.println(items.getName()+" : "+items.getDetail());
items.setDetail("不错!");
itemsMapper.updateByPrimaryKeyWithBLOBs(items);
}
}
3.项目结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GV9VaRqG-1641215111342)(image/image-20210304203733368.png)]
十二.作业
1.完成用户的修改和删除功能
2.使用sql片段实现需求
需求:通过性别和姓名查询用户列表,且id值是15或20或25 PS:不允许性别或者姓名为null或者空串
select * from user where sex=1 and username like concat('%','明','%') and (id=15 or id=20 or id=25);
3.完成高级映射
需求:查询订单、订单明细的信息及下单的用户信息
面试:
1.mybatis和hibernate的本质区别和应用场景
1.本质区别:
hibernate:是一个标准ORM框架(对象关系映射)。入门门槛较高的,不需要程序员写sql,sql语句自动生成了。对sql语句进行优化、修改比较困难的。
mybatis:专注是sql本身,需要程序员自己编写sql语句,sql修改、优化比较方便。mybatis是一个不完全的ORM框架,虽然程序员自己写sql,mybatis 也可以实现映射(输入映射、输出映射)。
2.应用场景:
hibernate的应用场景:
适用与需求变化不多的中小型项目,比如:后台管理系统,erp、orm、oa。
mybatis的应用场景:
适用与需求变化较多的项目,比如:互联网项目(京东、淘宝。。)
企业进行技术选型,以低成本高回报作为技术选型的原则,根据项目组的技术力量进行选择。
2.${}和#{}的区别
<select id="selectListByLikeName" parameterType="String" resultType="User">
select * from user where username like concat('%',#{username},'%')
</select>
@Test
public void selectListByLikeName(){
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = userMapper.selectListByLikeName("明");
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
|