🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[mybatis依赖jar包](https://pan.baidu.com/s/1WOkB-Uj4UuX4JsJWMsD55Q) *** ### 创建数据库 ``` -- ---------------------------- -- Table structure for user -- ---------------------------- DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(32) NOT NULL COMMENT '用户名称', `birthday` date DEFAULT NULL COMMENT '生日', `sex` char(1) DEFAULT NULL COMMENT '性别', `address` varchar(256) DEFAULT NULL COMMENT '地址', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of user -- ---------------------------- INSERT INTO `user` VALUES ('1', '王五', null, '2', null); INSERT INTO `user` VALUES ('10', '张三', '2014-07-10', '1', '北京市'); INSERT INTO `user` VALUES ('16', '张小明', null, '1', '河南郑州'); INSERT INTO `user` VALUES ('22', '陈小明', null, '1', '河南郑州'); INSERT INTO `user` VALUES ('24', '张三丰', null, '1', '河南郑州'); INSERT INTO `user` VALUES ('25', '陈小明', null, '1', '河南郑州'); ``` ## Mybatis框架原理(掌握) ### 1、Mybatis 是什么? Mybatis 是一个持久层的[架构](),是 apache 下的顶级项目。 Mybatis 原先是托管在 googlecode 下,再后来是托管在 Github 上。 Mybatis 让程序员将主要的精力放在 sql 上,通过 Mybatis 提供的映射方式,自由灵活生成(半自动,大部分需要程序员编写 sql )满足需要 sql 语句。 Mybatis 可以将向 preparedStatement 中的输入参数自动进行**输入映射**,将查询结果集灵活的映射成 java 对象。(**输出映射**) ### 2、Mybatis 框架 ![image.png](https://upload-images.jianshu.io/upload_images/468490-62f6533055625a20.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 注解: > * SqlMapConfig.xml (Mybatis的全局配置文件,名称不定)配置了数据源、事务等 Mybatis 运行环境 > > > * Mapper.xml 映射文件(配置 sql 语句) > > > * SqlSessionFactory (会话工厂)根据配置文件配置工厂、创建 SqlSession > > > * SqlSession (会话)面向用户的接口、操作数据库(发出 sql 增删改查) > > > * Executor (执行器)是一个接口(基本执行器、缓存执行器)、SqlSession 内部通过执行器操作数据库 > > > * Mapped Statement (底层封装对象)对操作数据库存储封装,包括 sql 语句、输入参数、输出结果类型 > ## Mybatis入门程序 ### 1、需求 实现以下功能: > * 根据用户id查询一个用户信息 > * 根据用户名称模糊查询用户信息列表 > * 添加用户 > * 更新用户 > * 删除用户 ### 2、环境 java 环境 :jdk1.8.0_77 开发工具 : IDEA 2016.1 数据库 : MySQL 5.7 Mybatis 运行环境( jar 包) MySQL 驱动包 其他依赖包 ### 3、 log4j.properties 在classpath下创建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 ``` Mybatis默认使用log4j作为输出日志信息。 ### 4、工程结构 ![image.png](https://upload-images.jianshu.io/upload_images/468490-4c8dbd1949ea12ac.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ### db.properties ``` jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql:///mybatis jdbc.username=root jdbc.password=root ``` ### 5、SqlMapConfig.xml 配置 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> <properties resource="db.properties"></properties> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments> <mappers> <package name="com.mapper"></package> </mappers> </configuration> ``` ### 6、创建domain类 domain 类作为 mybatis 进行 sql 映射使用,po 类通常与数据库表对应,User.java 如下: ``` package com.company.domain; import java.util.Date; /** * Created by Administrator on 2017/10/21. */ public class User { private int id; private String username; private Date birthday; private String sex; private String 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 Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } } ``` ### Mybatis 的 mapper 接口 思路 程序员需要编写mapper接口(相当于Dao接口,增删改查操作) 程序员需要编写 mapper.xml 映射文件,需遵循一些开发规范,mybatis 可以自动生成 mapper 接口类代理对象。 开发规范: 1.在 mapper.xml 中 namespace 等于 mapper 接口地址(所在包名的全路径) <mapper namespace="com.mapper.UserMapper"></mapper> 2.在 xxxmapper.java 接口中的方法名要与 xxxMapper.xml 中 statement 的 id 一致。 3.在 xxxmapper.java 接口中的输入参数类型要与 xxxMapper.xml 中 statement 的 parameterType 指定的参数类型一致。 4.在 xxxmapper.java 接口中的返回值类型要与 xxxMapper.xml 中 statement 的 resultType 指定的类型一致。 5.接口文件名要与xml映射文件名一致(UserMapper.java和UserMapper.xml) ### 7、根据用户 id(主键)查询用户信息 定义Mapper接口 ``` public interface UserMapper { public User findUserById(int id); } ``` 定义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.mapper.UserMapper"> <select id="findUserById" parameterType="int" resultType="com.domain.User"> select * from user where id = #{1} </select> </mapper> ``` 主方法测试 ``` public static void main(String[] args) throws IOException { //创建sqlSessionFactory //Mybatis 配置文件 String resource = "SqlMapConfig.xml"; //得到配置文件流 InputStream inputStream = Resources.getResourceAsStream(resource); //创建会话工厂,传入Mybatis的配置文件信息 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); //创建usermapper对象,mybatis自动生成代理对象 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //调用UserMapper的方法 User user = userMapper.findUserById(1); System.out.println(user.getUsername()); } ``` parameterType:指定输入参数类型,mybatis 从输入对象中获取参数值拼接在 sql 中。 resultType:指定输出结果类型,mybatis 将 sql 查询结果的一行记录数据映射为 resultType 指定类型的对象。 ### Sqlsession 的使用范围 SqlSession 中封装了对数据库的操作,如:查询、插入、更新、删除等。 通过 SqlSessionFactory 创建 SqlSession,而 SqlSessionFactory 是通过 SqlSessionFactoryBuilder 进行创建。 ### 1、SqlSessionFactoryBuilder SqlSessionFactoryBuilder 用于创建 SqlSessionFacoty,SqlSessionFacoty 一旦创建完成就不需要SqlSessionFactoryBuilder 了,因为 SqlSession 是通过 SqlSessionFactory 生产,所以可以将SqlSessionFactoryBuilder 当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量。 ### 2、SqlSessionFactory SqlSessionFactory 是一个接口,接口中定义了 openSession 的不同重载方法,SqlSessionFactory 的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,通常以单例模式管理 SqlSessionFactory。 ### 3、SqlSession SqlSession 是一个面向用户的接口, sqlSession 中定义了数据库操作,默认使用 DefaultSqlSession 实现类。 ### 单例模式的SqlSessionFactory ``` public class SqlSessionFactoryUtil { //首先创建静态成员变量sqlSessionFactory,静态变量被所有的对象所共享。 public static SqlSessionFactory sqlSessionFactory = null; public static SqlSessionFactory getSqlSessionFactory() { //如果sqlSessionFactory没有被创建就读取全局配置文件,假如已经被创建过了,就使用已经存在的sqlsessionfactory。 //这样就有了单例模式的效果 if(sqlSessionFactory==null){ String resource = "SqlMapConfig.xml"; try { Reader reader = Resources.getResourceAsReader(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return sqlSessionFactory; } } ``` 主方法测试变为: ``` public static void main(String[] args) throws IOException { //创建sqlSessionFactory SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory(); SqlSession sqlSession = sqlSessionFactory.openSession(); //创建usermapper对象,mybatis自动生成代理对象 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //调用UserMapper的方法 User user = userMapper.findUserById(1); System.out.println(user.getUsername()); } ``` ### 自定义别名: 在 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> <properties resource="db.properties"></properties> <typeAliases> <!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) --> <package name="com.domain"/> </typeAliases> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments> <mappers> <package name="com.mapper"></package> </mappers> </configuration> ``` ### 查找全部用户 UserMapper.java ``` public interface UserMapper { public User findUserById(int id); public List<User> findAllUsers(); //添加用户信息 public int addUser(User user); //删除用户信息 public int deleteUser(int id); public int updateUserById(User user); } ``` 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.mapper.UserMapper"> <select id="findUserById" parameterType="int" resultType="User"> select * from user where id = #{1} </select> <select id="findAllUsers" resultType="User"> select * from user </select> </mapper> ``` 主方法测试 ``` public static void main(String[] args) throws IOException { //创建sqlSessionFactory SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory(); SqlSession sqlSession = sqlSessionFactory.openSession(); //创建usermapper对象,mybatis自动生成代理对象 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //调用UserMapper的方法 // User user = userMapper.findUserById(1); // System.out.println(user.getUsername()); List<User> userList = userMapper.findAllUsers(); for(User user : userList) { System.out.println(user.getUsername()); } } ``` >虽然 findAllUsers()的返回值类型是List<User>,xml文件中resultType="User"即可。 ### 新增用户 ``` <insert id="addUser" parameterType="User" > <selectKey keyProperty="id" order="AFTER" resultType="int"> select LAST_INSERT_ID() </selectKey> insert into user(username, birthday, sex, address) values(#{username}, #{birthday}, #{sex}, #{address}) </insert> ``` 主函数 ``` User user = new User(); SimpleDateFormat sdf = new SimpleDateFormat ("yyyy-MM-dd"); user.setUsername("田志"); user.setSex("男"); user.setBirthday(sdf.parse("2016-11-29")); user.setAddress("江西南昌"); userMapper.addUser(user); System.out.println(user.getId()); sqlSession.commit(); ``` >增删改操作需要 sqlSession.commit(); ### 自增主键返回 MySQL 自增主键:执行 insert 提交之前自动生成一个自增主键,通过 MySQL 函数获取到刚插入记录的自增主键: LAST_INSERT_ID() ,是在 insert 函数之后调用。 ### 删除用户 ``` <delete id="deleteUser" parameterType="int"> delete from user where user.id = #{id} </delete> ``` ``` userMapper.deleteUser(1); sqlSession.commit(); ``` ### 更新用户 ``` <update id="updateUserById" parameterType="User"> update user set username = #{username}, birthday = #{birthday}, sex = #{sex}, address = #{address} where user.id = #{id} </update> ``` ``` SimpleDateFormat sdf = new SimpleDateFormat ("yyyy-MM-dd"); User user = new User(); //根据id更新用户信息 user.setId(24); user.setUsername("张四风2"); user.setBirthday(sdf.parse("2015-01-12")); user.setSex("女"); user.setAddress("上海黄埔"); userMapper.updateUserById(user); //提交事务 sqlSession.commit(); ``` ### 模糊查找用户 ``` <select id="findUserList" parameterType="User" resultType="User"> select * from user where user.sex = #{sex} and user.username like #{username} </select> ``` ``` User user = new User(); user.setSex("1"); user.setUsername("%张%"); //调用UserMapper的方法 List<User> list = userMapper.findUserList(user); for(User u : list) { System.out.println(u.getUsername()); } ``` ### 查找user表记录数 ``` <select id="findUserCount" resultType="int"> select count(*) from user </select> ``` ``` int count = userMapper.findUserCount(); System.out.println(count); ``` ### 动态 SQL 通过mybatis提供的各种标签方法实现动态拼接sql。 ``` <select id="findUserList2" parameterType="User" resultType="User"> select * from user <!--where可以自动的去掉条件中的第一个and--> <where> <if test="sex != null and sex != ''"> and user.sex = #{sex} </if> <if test="username != null"> and user.username like #{username} </if> </where> </select> ``` 测试代码:因为设置了动态的sql,如果不设置某个值,那么条件就不会拼接在sql上 所以我们就注释掉设置username的语句 ``` User user = new User(); // user.setSex("1"); user.setUsername("%张%"); //调用UserMapper的方法 List<User> list = userMapper.findUserList2(user); for(User u : list) { System.out.println(u.getUsername()); } ``` ### Sql 片段 通过上面的其实看到在 where sql语句中有很多重复代码,我们可以将其抽取出来,组成一个sql片段,其他的statement就可以引用这个sql片段,利于系统的开发。 这里我们就拿上边sql 中的where定义一个sq片段如下: ``` <sql id="query_user_where"> <if test="sex != null and sex != ''"> and user.sex = #{sex} </if> <if test="username != null"> and user.username like #{username} </if> </sql> ``` 那么我们该怎样引用这个sql片段呢?如下: ``` select * from user <where> <!--refid: 指定sql片段的id,如果是写在其他的mapper文件中,则需要在前面加上namespace--> <include refid="query_user_where"/> </where> ``` ### 多表连接 再创建一个订单信息表 ``` CREATE TABLE `orders` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL COMMENT '下单用户id', `number` varchar(32) NOT NULL COMMENT '订单号', `createtime` datetime NOT NULL COMMENT '创建订单时间', `note` varchar(100) DEFAULT NULL COMMENT '备注', PRIMARY KEY (`id`), KEY `FK_orders_1` (`user_id`), CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of orders -- ---------------------------- INSERT INTO `orders` VALUES ('3', '1', '1000010', '2015-02-04 13:22:35', null); INSERT INTO `orders` VALUES ('4', '1', '1000011', '2015-02-03 13:22:41', null); INSERT INTO `orders` VALUES ('5', '10', '1000012', '2015-02-12 16:13:23', null); ``` ``` public List<Map<String,Object>> getAllOrderInfo(); ``` ``` <select id="getAllOrderInfo" resultType="map"> select orders.number,user.username from orders join user on orders.user_id = user.id </select> ``` ``` List<Map<String,Object>> mapList = userMapper.getAllOrderInfo(); for(Map<String,Object> map : mapList) { System.out.println("---------------"); for(Map.Entry<String,Object> entry : map.entrySet()) { System.out.println(entry.getKey()+" "+entry.getValue()); } } ``` ### 代码 [案例代码](https://github.com/songboriceboy/grasp_mybatis_oneday)