0%

java之mybatis

说明

  • 上篇文章 主要用jsp+jdbc的方式进行了练习,本次采用ORM框架mybatis代替jdbc,实现增删改查

  • java版本为1.8

  • 本次练习源代码

配置

  • pom.xml中加入依赖文件
1
2
3
4
5
6
7
8
9
10
 <dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.11</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.13</version>
</dependency>
  • 新增一个实例类 src-main-java-xyz.shi.entity.User
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 xyz.shi.entity;
public class User {
private int id;
private String name;
private String password;
public int getId() {
return id;
}
public User () {

}
public User(int id,String name, String password) {
this.name = name;
this.id = id;
this.password = password;
}

public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setPassword(String password) {
this.password = password;
}
public String getPassword() {
return password;
}

}
  • 接下来就要创建一个xml文件作为MyBatis的核心配置文件了,src-main-resources-mybatis.config.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?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标签,当mybatis和spring整合之后,这个标签是不用配置的 -->

<!-- 可以配置多个运行环境,但是每个 SqlSessionFactory 实例只能选择一个运行环境
一、development:开发模式
二、work:工作模式-->
<environments default="development">
<!--id属性必须和上面的default一样 -->
<environment id="development">
<!--事务管理器
一、JDBC:这个配置直接简单使用了 JDBC 的提交和回滚设置。它依赖于从数据源得到的连接来管理事务范围
二、MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接。而它会让容器来管理事务的整个生命周期
比如 spring 或 JEE 应用服务器的上下文,默认情况下,它会关闭连接。然而一些容器并不希望这样,
因此如果你需要从连接中停止它,就可以将 closeConnection 属性设置为 false,比如:
<transactionManager type="MANAGED">
<property name="closeConnection" value="false"/>
</transactionManager>
-->
<transactionManager type="JDBC"/>
<!--dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象源 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai" />
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>

</configuration>

替换连接信息解决硬编码问题

  • 编写sql映射文件了,src-main-resources-UserMapper.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?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="usersMapper">

<!-- 根据 id 查询 users 表中的数据
id:唯一标识符,此文件中的id值不能重复
resultType:返回值类型,一条数据库记录也就对应实体类的一个对象
parameterType:参数类型,也就是查询条件的类型
-->
<select id="selectusersById"
resultType="xyz.shi.entity.User" parameterType="int">
<!-- 这里和普通的sql 查询语句差不多,对于只有一个参数,后面的 #{id}表示占位符,里面不一定要写id,写啥都可以,但是不要空着,如果有多个参数则必须写pojo类里面的属性 -->
select * from users where id = #{id}
</select>


<!-- 查询 users 表的所有数据
注意:因为是查询所有数据,所以返回的应该是一个集合,这个集合里面每个元素都是users类型
-->
<select id="selectusersAll" resultType="xyz.shi.entity.User">
select * from users
</select>

<!-- 模糊查询:根据 users 表的usersname字段
下面两种写法都可以,但是要注意
1、${value}里面必须要写value,不然会报错
2、${}表示拼接 sql 字符串,将接收到的参数不加任何修饰拼接在sql语句中
3、使用${}会造成 sql 注入
-->
<select id="selectLikeusersName" resultType="xyz.shi.entity.User" parameterType="String">
select * from users where name like '%${value}%'
<!-- select * from users where usersname like #{usersname} -->
</select>

<!-- 向 users 表插入一条数据 -->
<insert id="insertusers" parameterType="xyz.shi.entity.User">
insert into users(name,password)
value(#{name},#{password})
</insert>

<!-- 根据 id 更新 users 表的数据 -->
<update id="updateusersById" parameterType="xyz.shi.entity.User">
update users set name=#{name},password=#{password} where id=#{id}
</update>

<!-- 根据 id 删除 users 表的数据 -->
<delete id="deleteusersById" parameterType="int">
delete from users where id=#{id}
</delete>
</mapper>

统一管理sql语句,解决硬编码问题

  • src-main-resources-mybatis-config.xml 配置文件中注册 userMapper.xml 文件
1
2
3
4
5
6
...
</environment>
<mappers>
<!-- 注册userMapper.xml文件 -->
<mapper resource="UserMapper.xml"/>
</mappers>

测试代码

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

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 xyz.shi.entity.User;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class CRUDTest {
public static void main(String[] args) throws IOException {
//1. 加载mybatis的核心配置文件,获取 SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

//2. 获取SqlSession对象,用它来执行sql
SqlSession sqlSession = sqlSessionFactory.openSession();
//3. 执行sql (只有这块需要手写,其他步骤直接复制)
List<User> users = sqlSession.selectList("usersMapper.selectusersAll"); // 命名空间+id,这就是命名空间的作用:便于区分
// System.out.println(users);
for(User user: users) {
System.out.println(user.getId());
System.out.println(user.getName());
System.out.println(user.getPassword());
}

// 插入
User user1 = new User();
user1.setName("haha");
user1.setPassword("111111");
sqlSession.insert("usersMapper.insertusers", user1);
sqlSession.commit();

// 修改
User user2 = new User();
user2.setId(1);
user2.setName("haha");
user2.setPassword("111111");
sqlSession.update("usersMapper.updateusersById", user2);
sqlSession.commit();

//删除
User user3= new User();
user3.setId(24);
sqlSession.delete("usersMapper.deleteusersById", user3);
sqlSession.commit();


sqlSession.close();
}

}

优化架构

mybatis-config

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?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"/>
<settings>
<!--设置日志-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!--开启驼峰命名,映射数据库到对象属性名-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!--开启缓存-->
<setting name="cacheEnabled" value="true"/>
</settings>

<!--给实体类取别名,为了后面配置mapper.xml时不用写全限定名,方便使用-->
<typeAliases>
<!--包扫描-->
<package name="xyz.shi.entity"/>
</typeAliases>

<environments default="development">
<!--id属性必须和上面的default一样 -->
<environment id="development">
<!--事务管理器
一、JDBC:这个配置直接简单使用了 JDBC 的提交和回滚设置。它依赖于从数据源得到的连接来管理事务范围
二、MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接。而它会让容器来管理事务的整个生命周期
比如 spring 或 JEE 应用服务器的上下文,默认情况下,它会关闭连接。然而一些容器并不希望这样,
因此如果你需要从连接中停止它,就可以将 closeConnection 属性设置为 false,比如:
<transactionManager type="MANAGED">
<property name="closeConnection" value="false"/>
</transactionManager>
-->
<transactionManager type="JDBC"/>
<!--dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象源 -->
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${user}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- 注册userMapper.xml文件 -->
<mapper resource="UserMapper.xml"/>
</mappers>

</configuration>

UserMapper.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?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="usersMapper">

<!-- 根据 id 查询 users 表中的数据
id:唯一标识符,此文件中的id值不能重复
resultType:返回值类型,一条数据库记录也就对应实体类的一个对象
parameterType:参数类型,也就是查询条件的类型
-->

<!--通过id(唯一)获取用户-->
<select id="queryById" parameterType="int" resultType="User">
select * from users where id = #{id};
</select>

<select id="queryOne" resultType="User" parameterType="map">
select * from users where name = #{name} and password=#{password};
</select>
<!-- <select id="getUserList" parameterType="map" resultType="User">-->
<select id="getUserList" resultType="User">
select * from users
<!-- <if test="name != null">-->
<!-- and name = #{name}-->
<!-- </if>-->
<!-- <if test="password != null">-->
<!-- and password = #{password}-->
<!-- </if>-->
<!-- <trim prefix="limit">-->
<!-- <if test="curPage != null and pageSize != null">-->
<!-- #{curPage},#{pageSize}-->
<!-- </if>-->
<!-- </trim>-->
</select>

<!-- 向 users 表插入一条数据 -->
<insert id="addUser" parameterType="User">
insert into users(name,password)
value(#{name},#{password})
</insert>

<update id="modify" parameterType="User">
update users set name=#{name},password=#{password} where id=#{id}
</update>

<!-- 根据 id 删除 users 表的数据 -->
<delete id="deleteById" parameterType="int">
delete from users where id=#{id}
</delete>
</mapper>

三层架构

实体层(entity)

  • User.java 代码省略

数据访问层(Dao)

  • 接口类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package xyz.shi.dao;

import xyz.shi.entity.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;

public interface UserDao {
List<User> getUserList();
User queryOne(User user);
User queryById(int id);
// //通过id删除用户
int deleteById(@Param("id")int id);
int addUser(User user);

int modify(User user);
}

  • 实现接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package xyz.shi.dao.impl;

import org.apache.ibatis.session.SqlSession;
import xyz.shi.dao.UserDao;
import xyz.shi.entity.User;

import java.util.List;
import java.util.Map;
import xyz.shi.utils.MybatisUtils;
public class UserDaoImpl implements UserDao {

@Override
public List<User> getUserList() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
// 命名空间+id,这就是命名空间的作用:便于区分
List<User> users = sqlSession.selectList("usersMapper.getUserList");
sqlSession.close();
return users;
}

@Override
public User queryOne(User user) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
List<User> users = sqlSession.selectList("usersMapper.queryOne", user);
sqlSession.close();
if (users != null) {
return users.get(0);
} else {
return null;
}
}

@Override
public User queryById(int id) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
User user1 = sqlSession.selectOne("usersMapper.queryById", id);
sqlSession.close();
return user1;
}

@Override
public int deleteById(int id) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
int num = sqlSession.delete("usersMapper.deleteById", id);
sqlSession.commit();
sqlSession.close();
return num;
}

@Override
public int addUser(User user) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
int num = sqlSession.insert("usersMapper.addUser", user);
sqlSession.commit();
sqlSession.close();
return num;
}

@Override
public int modify(User user) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
int num = sqlSession.update("usersMapper.modify", user);
sqlSession.commit();
sqlSession.close();
return num;
}
}

业务逻辑(services)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package xyz.shi.service;

import xyz.shi.entity.User;

import java.util.List;
public interface UserService {
List<User> getUserList();
User queryOne(User user);
User queryById(int id);
int deleteById(int id);
int addUser(User user);
int modify(User user);

}

  • 实现接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package xyz.shi.service.impl;

import xyz.shi.dao.UserDao;
import xyz.shi.dao.impl.UserDaoImpl;
import xyz.shi.entity.User;
import xyz.shi.service.UserService;
import java.util.List;

public class UserServiceImpl implements UserService {
//创建UserDaoImpl对象
private UserDao userDao = new UserDaoImpl();

@Override
public List<User> getUserList() {
return userDao.getUserList();
}

@Override
public User queryOne(User user) {
return userDao.queryOne(user);
}

@Override
public User queryById(int id) {
return userDao.queryById(id);
}

@Override
public int deleteById(int id) {
return userDao.deleteById(id);
}

@Override
public int addUser(User user) {
return userDao.addUser(user);
}

@Override
public int modify(User user) {
return userDao.modify(user);
}
}

servlet层

  • 接受jsp数据,传送数据到jsp页面,比如下面的用户详情页
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
package xyz.shi.servlet;

import xyz.shi.entity.User;
import xyz.shi.service.UserService;
import xyz.shi.service.impl.UserServiceImpl;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/userFind")
public class FindUserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
UserService userService = new UserServiceImpl();
int userId = Integer.parseInt(req.getParameter("id"));
User user = userService.queryById(userId);
if (user != null) {
req.setAttribute("user", user);
req.getRequestDispatcher("find.jsp").forward(req, resp);
} else {
// 登录失败,返回登录页面
System.out.println("查找数据失败");
req.setAttribute("message", "failed");

}
}
}

view层

webapp/下面的login、add、find等jsp文件,用户详情页,并进行修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>添加用户</title>
</head>
<body>
<div><a href="login">主页</a></div>
<form action="userUpdate" method="post">
用户名:<br>
<input type="text" name="username" value="${user.getName()}">
<br>
密码:<br>
<input type="password" name="password" value="${user.getPassword()}" >
<input type="hidden" name="id" value="${user.getId()}">
<br><br>
<input type="submit" value="提交" >
</form>

</body>
</html>

页面

image-20231212113144060