Mybatis 代码实践

Mybatis 代码实践 作者:密叔
Mybatis 是什么? Mybatis 是一个持久层框架。Java 中通过 Mybatis ,程序可以很方便的对数据库进行操作。使开发者专注于 SQL语句,避免了重复的 JDBC 代码。

  • 使用 MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集
  • 灵活且强大,支持定制化 SQL、存储过程以及高级映射
  • 支持 XML 和注解两种形式编写 SQL
  • 数据库中的记录可以映射为普通 Java 对象

准备 环境:
开发工具:IDEA
包管理:Maven
JDK:1.8
Mybatis :Mybatis 3.4.6

问题场景
使用 Mybatis 完成基于简单权限设计的数据库表的相关操作、查询
涉及到的表
t_user t_user_info t_role t_menu t_user_role //关系表 t_role_menu //关系表

要做哪些操作
  • t_user 表的简单增删改成
  • 关联复杂查询,查询一个用户的所有权限信息
  • 动态查询,包含某些菜单权限的用户

1、新建数据库表,初始化些数据
-- ---------------------------- --Table structure for `t_menu` -- ---------------------------- DROP TABLE IF EXISTS `t_menu`; CREATE TABLE `t_menu` ( `id` int(10) NOT NULL AUTO_INCREMENT, `name` varchar(50) DEFAULT NULL, `type` int(11) DEFAULT NULL, `url` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8; ? -- ---------------------------- --Table structure for `t_role` -- ---------------------------- DROP TABLE IF EXISTS `t_role`; CREATE TABLE `t_role` ( `id` int(10) NOT NULL AUTO_INCREMENT, `name` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; ? -- ---------------------------- --Table structure for `t_role_menu` -- ---------------------------- DROP TABLE IF EXISTS `t_role_menu`; CREATE TABLE `t_role_menu` ( `role_id` int(10) DEFAULT NULL, `menu_id` int(10) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; ? -- ---------------------------- --Table structure for `t_user` -- ---------------------------- DROP TABLE IF EXISTS `t_user`; CREATE TABLE `t_user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(50) DEFAULT NULL, `password` varchar(50) DEFAULT NULL, `nickname` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `t_user_username_uindex` (`username`) ) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8; ? -- ---------------------------- --Table structure for `t_user_role` -- ---------------------------- DROP TABLE IF EXISTS `t_user_role`; CREATE TABLE `t_user_role` ( `user_id` int(10) DEFAULT NULL, `role_id` int(10) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; ? SET FOREIGN_KEY_CHECKS = 1; ? -- ---------------------------- --Table structure for `t_user_info` -- ---------------------------- DROP TABLE IF EXISTS `t_user_info`; CREATE TABLE `t_user_info` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) DEFAULT NULL, `name` varchar(100) COLLATE utf8_bin DEFAULT NULL, `email` varchar(100) COLLATE utf8_bin DEFAULT NULL, `address` varchar(255) COLLATE utf8_bin DEFAULT NULL, `phone` varchar(20) COLLATE utf8_bin DEFAULT NULL, `sex` varchar(2) COLLATE utf8_bin DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_bin; ? SET FOREIGN_KEY_CHECKS = 1;

手动初始化些数据进去,构建一些关联数据,为下面测试所用

2、构建Maven项目

组织 project 目录
└── src ├── main │├── java ││└── me ││└── imcoding ││├── dao ││├── mapper ││├── model │└── resources │└── mapper └── test └── java └── me └── imcoding ?


3、引入 Mybatis 相关依赖
在 maven 环境中,需要在 pom.xml 文件中增加依赖
org.mybatis mybatis 3.4.6 mysql mysql-connector-java 5.1.46 com.alibaba fastjson 1.2.31 junit junit 4.11 test ?


4、配置 Mybatis
在 resources 目录新建 mybatis-config.xml
└── resources ├── mapper └── mybatis-config.xml

配置以下内容
? ?

外部属性配置,resources 目录下新增 dbconfig.properties 文件
└── resources ├── dbconfig.properties ├── mapper └── mybatis-config.xml

配置内容:
driver=com.mysql.jdbc.Driver url=jdbc:mysql://127.0.0.1:3306/mybatis-demo?useUnicode=true&characterEncoding=utf8 username=root password=root

数据库连接的相关属性信息

5、获取 SqlSession
核心代码:
// 配置文件位置 String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession = factory.openSession();

写个工具类 MybatisUtils:
├── java └── me └── imcoding ├── App.java ├── MybatisUtils.java

? public class MybatisUtils { ? private static SqlSessionFactory factory; ? /** * 根据 mybatis-config.xml 配置初始化 factory */ private static void initialFactory() { String resource = "mybatis-config.xml"; try { InputStream in = Resources.getResourceAsStream(resource); factory = new SqlSessionFactoryBuilder().build(in); } catch (IOException e) { e.printStackTrace(); } } ?public static SqlSession getSession() { if (factory == null) { initialFactory(); } // factory.openSession(true) - 开启事务自动提交 SqlSession sqlSession = factory.openSession(); return sqlSession; } } ?



基本增删改查(CURD) 1、构建 Model 类
目录:
├── model ├── Menu.java ├── Role.java └── User.java

User
public class User { private Integer id; private String username; private String password; private String nickname; ? /*setter 和 getter 省略*/ }

Role
public class Role { private Integer id; private String name; // setter 和 getter 方法省略... }

Menu
public class Menu { private Integer id; private String name; private int type; private String url; // setter and getter ... }


UserInfo
public class UserInfo { ? private Integer id; private String name; private String sex; private String address; private String phone; private String email; //setter and getter.... }


2. 构建 Mapper 接口
目录:
├── mapper └── UserMapper.java

UserMapper
public interface UserMapper { ? // 新增 User int insertUser(User user); ? // 根据主键删除 int deleteUser(int id); ? // 更新 User int updateUser(User user); ? // 根据主键 id 查询 User selectByKey(int id); ? // 根据用户名和密码查询 User selectByUsernameAndPassword(String username, String password); }


3、定义 Mapper xml
新建 UserMapper.xml
└── resources ├── dbconfig.properties ├── mapper │└── UserMapper.xml └── mybatis-config.xml

UserMapper.xml
? ? insert into t_user(username, password, nickname) values (#{username}, #{password}, #{nickname}) ? delete from t_user where id = #{id} ? update t_userusername = #{username} password = #{password} nickname = #{nickname}where id = #{id} ?select nickname, username, password from t_user where id = #{id}?select nickname, username, password from t_user username = #{username} and password = #{password} ? ?


一定不要忘记在 mybatis-config.xml 中引入 UserMapper.xml
mybatis-config.xml
?


4、构建 UserDao
目录:
└── imcoding ├── App.java ├── MybatisUtils.java ├── dao └── UserDao.java

UserDao
? /** * Author:密叔. */ public class UserDao { ? // 新增 public int insertUser(User user) { SqlSession sqlSession = MybatisUtils.getSession(); int bo; try { // 从 sqlSession 中获取 Mapper 实例 UserMapper mapper = sqlSession.getMapper(UserMapper.class); // 调用 mapper 的方法 bo = mapper.insertUser(user); sqlSession.commit(); //提交事务 return bo; } finally { //一定要关闭 sqlSession sqlSession.close(); } } ? // 删除 public int deleteUser(int id) { SqlSession sqlSession = MybatisUtils.getSession(); int bo; try { // 从 sqlSession 中获取 Mapper 实例 UserMapper mapper = sqlSession.getMapper(UserMapper.class); // 调用 mapper 的方法 bo = mapper.deleteUser(id); sqlSession.commit(); //提交事务 return bo; } finally { //一定要关闭 sqlSession sqlSession.close(); } } ? // 更新 public int updateUser(User user) { SqlSession sqlSession = MybatisUtils.getSession(); int bo; try { // 从 sqlSession 中获取 Mapper 实例 UserMapper mapper = sqlSession.getMapper(UserMapper.class); // 调用 mapper 的方法 bo = mapper.updateUser(user); sqlSession.commit(); //提交事务 return bo; } finally { //一定要关闭 sqlSession sqlSession.close(); } } ? // 查询 public User selectUser(int id) { SqlSession sqlSession = MybatisUtils.getSession(); User user; try { // 从 sqlSession 中获取 Mapper 实例 UserMapper mapper = sqlSession.getMapper(UserMapper.class); // 调用 mapper 的方法 user = mapper.selectUser(id); sqlSession.commit(); //提交事务 return user; } finally { //一定要关闭 sqlSession sqlSession.close(); } } ? ? // 根据 username 和 password 查询 public User selectByUsernameAndPassword(String username, String password) { SqlSession sqlSession = MybatisUtils.getSession(); User user; try { // 从 sqlSession 中获取 Mapper 实例 UserMapper mapper = sqlSession.getMapper(UserMapper.class); // 调用 mapper 的方法 user = mapper.selectByUsernameAndPassword(username, password); sqlSession.commit(); //提交事务 return user; } finally { //一定要关闭 sqlSession sqlSession.close(); } } ? ? } ?


5、测试
目录:
└── test └── java └── me └── imcoding └── AppTest.java

AppTest
? /** * Author:密叔. */ public class UserDao { ? // 新增 public int insertUser(User user) { SqlSession sqlSession = MybatisUtils.getSession(); int bo; try { // 从 sqlSession 中获取 Mapper 实例 UserMapper mapper = sqlSession.getMapper(UserMapper.class); // 调用 mapper 的方法 bo = mapper.insertUser(user); sqlSession.commit(); //提交事务 return bo; } finally { //一定要关闭 sqlSession sqlSession.close(); } } ? // 删除 public int deleteUser(int id) { SqlSession sqlSession = MybatisUtils.getSession(); int bo; try { // 从 sqlSession 中获取 Mapper 实例 UserMapper mapper = sqlSession.getMapper(UserMapper.class); // 调用 mapper 的方法 bo = mapper.deleteUser(id); sqlSession.commit(); //提交事务 return bo; } finally { //一定要关闭 sqlSession sqlSession.close(); } } ? // 更新 public int updateUser(User user) { SqlSession sqlSession = MybatisUtils.getSession(); int bo; try { // 从 sqlSession 中获取 Mapper 实例 UserMapper mapper = sqlSession.getMapper(UserMapper.class); // 调用 mapper 的方法 bo = mapper.updateUser(user); sqlSession.commit(); //提交事务 return bo; } finally { //一定要关闭 sqlSession sqlSession.close(); } } ? // 查询 public User selectUser(int id) { SqlSession sqlSession = MybatisUtils.getSession(); User user; try { // 从 sqlSession 中获取 Mapper 实例 UserMapper mapper = sqlSession.getMapper(UserMapper.class); // 调用 mapper 的方法 user = mapper.selectUser(id); sqlSession.commit(); //提交事务 return user; } finally { //一定要关闭 sqlSession sqlSession.close(); } } ? ? // 根据 username 和 password 查询 public User selectByUsernameAndPassword(String username, String password) { SqlSession sqlSession = MybatisUtils.getSession(); User user; try { // 从 sqlSession 中获取 Mapper 实例 UserMapper mapper = sqlSession.getMapper(UserMapper.class); // 调用 mapper 的方法 user = mapper.selectByUsernameAndPassword(username, password); sqlSession.commit(); //提交事务 return user; } finally { //一定要关闭 sqlSession sqlSession.close(); } } ? } ?


复杂查询 查询某个 user 的详情与菜单权限
SQL:
SELECT u.id, u.username, u.password, u.nickname, ui.name, ui.sex, ui.email, ui.address, ui.phone, r.id as role_id, r.name as role_name, m.id as menu_id, m.name as menu_name FROM t_user u LEFT outer JOIN t_user_role ur ON u.id = ur.user_id LEFT outer JOIN t_role r ON r.id = ur.role_id left OUTER JOIN t_role_menu rm ON rm.role_id = r.id left outer join t_menu m on m.id = rm.menu_id left outer join t_user_info ui on u.id = ui.user_id WHERE u.username = 'fangf@163.com'


1、新增接口方法
UserMapper.java
public interface UserMapper { ? //....// 查询 user 详细信息,以map方式返回结果 User selectUserInfo(int id); //.... ? } ?


2、UserMapper.xml 新增查询
UserMapper.xml
.....SELECT u.id, u.username, u.password, u.nickname, ui.id as ui_id, ui.name as ui_name, ui.sex as ui_sex, ui.email as ui_email, ui.address as ui_address, ui.phone as ui_phone, r.id as role_id, r.name as role_name, m.id as menu_id, m.name as menu_name FROM t_user u LEFT outer JOIN t_user_role ur ON u.id = ur.user_id LEFT outer JOIN t_role r ON r.id = ur.role_id left OUTER JOIN t_role_menu rm ON rm.role_id = r.id left outer join t_menu m on m.id = rm.menu_id left outer join t_user_info ui on u.id = ui.user_id WHERE u.id = #{id}? ? ? ....


3、User 类新增属性和构造
User
public class User {// .... ? // 无参构造 public User() {} // id 参数构造,@Param("id") 与mapper xml 中的 name属性一致 public User(Integer id) { this.id = id; } ? private UserInfo userInfo; private List roles; private List menus; ? ? ? // ....} ?


4、UserDao 新增查询
UserDao
public class UserDao { ? //.... // 查询用户的所有详细信息 public User selectUserInfo(int id) { SqlSession sqlSession = MybatisUtils.getSession(); User user; try { // 从 sqlSession 中获取 Mapper 实例 UserMapper mapper = sqlSession.getMapper(UserMapper.class); // 调用 mapper 的方法 user = mapper.selectUserInfo(id); return user; } finally { //一定要关闭 sqlSession sqlSession.close(); } }//.... ? }


5、测试
AppTest
public class AppTest {//......@Test public void selectUserInfo() { UserDao dao = new UserDao(); User user = dao.selectUserInfo(1); System.out.println(JSON.toJSONString(user,true)); }//...... }


结果:
{ "id":1, "menus":[ { "id":1, "name":"站点信息", "type":0 }, { "id":2, "name":"车辆查询", "type":0 }, { "id":3, "name":"人员管理", "type":0 }, { "id":4, "name":"用户管理", "type":0 }, { "id":5, "name":"角色管理", "type":0 }, { "id":6, "name":"菜单管理", "type":0 }, { "id":7, "name":"站点维护", "type":0 } ], "nickname":"方方", "password":"111111", "roles":[ { "id":1, "name":"管理员" } ], "userInfo":{ "address":"上海闵行区58", "email":"fangf@163.com", "id":1, "name":"方达", "phone":"18276546543", "sex":"男" }, "username":"fangf@163.com" } ?


源码 mybatis-practice
Mybatis 知识边界
  • Mybatis 引入
  • Mybatis 的必要配置
  • Mybatis Mapper XML (映射文件)
  • Mybatis 动态 SQL
  • Mybatis SqlSession
  • Mybatis 代码生成
  • Mybatis 缓存
  • Mybatis 事务

学习资源:http://www.mybatis.org/mybatis-3/zh/index.html

Mybatis 核心知识
  • Mapper XML 映射文件的使用规则
    学习:http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html
  • 动态 SQL 的处理规则
    学习:http://www.mybatis.org/mybatis-3/zh/dynamic-sql.html

【Mybatis 代码实践】

    推荐阅读