{"id":18859054,"url":"https://github.com/rawchen/mybatis-study","last_synced_at":"2026-02-08T10:30:18.157Z","repository":{"id":107706620,"uuid":"288698957","full_name":"rawchen/MyBatisStudy","owner":"rawchen","description":"学习 MyBatis 的记录","archived":false,"fork":false,"pushed_at":"2020-11-03T12:53:00.000Z","size":3115,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-12-30T20:13:12.842Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rawchen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-08-19T10:12:36.000Z","updated_at":"2020-11-03T12:53:02.000Z","dependencies_parsed_at":null,"dependency_job_id":"c535765b-6259-4547-8bbb-b5decacabfb8","html_url":"https://github.com/rawchen/MyBatisStudy","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rawchen%2FMyBatisStudy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rawchen%2FMyBatisStudy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rawchen%2FMyBatisStudy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rawchen%2FMyBatisStudy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rawchen","download_url":"https://codeload.github.com/rawchen/MyBatisStudy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239800488,"owners_count":19699127,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-08T04:15:49.358Z","updated_at":"2026-02-08T10:30:18.075Z","avatar_url":"https://github.com/rawchen.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MyBatisStudy\r\n\r\n### MyBatis 3 学习记录4阶段\r\n\r\n--------------------------------------------------------\r\n\r\n**（1）mybatis入门**\r\n\r\n1. mybatis的概述\r\n2. mybatis的环境搭建\r\n3. mybatis入门案例\r\n4. 自定义mybatis框架（主要的目的是为了让大家了解mybatis中执行细节） \r\n\r\n---------------------------------------------------------------\r\n\r\n**（2）mybatis基本使用**\r\n\r\n1. mybatis的单表crud操作\r\n2. mybatis的参数和返回值\r\n3. mybatis的dao编写\r\n4. mybatis配置的细节\r\n5. 几个标签的使用\r\n\r\n**（3）mybatis的深入和多表**\r\n\r\n1. mybatis的连接池\r\n\r\n2. mybatis的事务控制及设计的方法\r\n\r\n3. mybatis的多表查询\r\n\r\n   一对多-----多对一------多对多\r\n\r\n**（4）mybatis的缓存和注解开发**\r\n\r\n1. mybatis中的加载时机（查询的时机）\r\n\r\n2. mybatis中的一级缓存和二级缓存\r\n\r\n3. mybatis的注解开发\r\n\r\n   单表CRUD------多表查询\r\n\r\n### 什么是框架？\r\n\r\n它是我们软件开发中的一套解决方案，不同的框架解决的是不同的问题。\r\n\r\n使用框架的好处：框架封装了很多的细节，使开发者可以使用极简的方式实现功能。大大提高开发效率。\r\n\r\n### 三层架构\r\n\r\n表现层：是用于展示数据的\r\n\r\n业务层：是处理业务需求\r\n\r\n持久层：是和数据库交互的\r\n\r\n### 持久层技术解决方案\r\n\r\n1. JDBC技术：**Connection**、**PreparedStatement**、**ResultSet**\r\n\r\n2. Spring的**JdbcTemplate**：Spring中对jdbc的简单封装\r\n\r\n3. Apache的**DBUtils**：它和Spring的JdbcTemplate很像，也是对Jdbc的简单封装\r\n\r\n   以上这些都不是框架，JDBC是规范，Spring的JdbcTemplate和Apache的DBUtils都只是工具类\r\n\r\n### mybatis的概述\r\n\r\nmybatis是一个持久层框架，用java编写的。\r\n\r\n它封装了jdbc操作的很多细节，使开发者只需要关注sql语句本身，而无需关注注册驱动，创建连接等繁杂过程。\r\n\r\n它使用了ORM思想实现了结果集的封装。\r\n\r\n**ORM：Object Relational Mappging 对象关系映射**\r\n\r\n简单的说：就是把数据库表和实体类及实体类的属性对应起来，让我们可以操作实体类就实现操作数据库表。\r\n\r\n\r\n\r\n## 01_01mybatis入门\r\n\r\n**建库建表：mybatistest.sql**\r\n\r\n```SQL\r\nDROP TABLE IF EXISTS `user`;\r\n\r\nCREATE TABLE `user` (\r\n  `id` int(11) NOT NULL auto_increment,\r\n  `username` varchar(32) NOT NULL COMMENT '用户名称',\r\n  `birthday` datetime default NULL COMMENT '生日',\r\n  `sex` char(1) default NULL COMMENT '性别',\r\n  `address` varchar(256) default NULL COMMENT '地址',\r\n  PRIMARY KEY  (`id`)\r\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\r\n\r\ninsert  into `user`(`id`,`username`,`birthday`,`sex`,`address`) \r\nvalues \r\n(41,'老王','2018-02-27 17:47:08','男','北京'),\r\n(42,'小二王','2018-03-02 15:09:37','女','福建'),\r\n(43,'小二王','2018-03-04 11:34:34','女','厦门'),\r\n(45,'老六','2018-03-04 12:04:06','男','西藏'),\r\n(46,'老王','2018-03-07 17:37:26','男','新疆'),\r\n(48,'小马宝莉','2018-03-08 11:44:00','女','湖南');\r\n```\r\n\r\n### mybatis的环境搭建：\r\n\r\n1. 创建maven工程并导入坐标\r\n\r\n2. 创建实体类和dao的接口\r\n\r\n3. 创建Mybatis的主配置文件\r\n\r\n   SqlMapConifg.xml\r\n\r\n4. 创建映射配置文件\r\n\r\n   UserDao.xml\r\n\r\n### 环境搭建的注意事项：\r\n\r\n1. 创建UserDao.xml 和 UserDao.java时名称是为了和我们之前的知识保持一致。在Mybatis中它把持久层的操作接口名称和映射文件也叫做：Mapper\r\n\r\n   所以：UserDao 和 UserMapper是一样的\r\n\r\n2. 在idea中创建目录的时候，它和包是不一样的\r\n\r\n   包在创建时：com.yoyling.dao它是三级结构\r\n\r\n   目录在创建时：com.yoyling.dao是一级目录\r\n\r\n3. mybatis的映射配置文件位置必须和dao接口的包结构相同\r\n\r\n4. 映射配置文件的mapper标签namespace属性的取值必须是dao接口的全限定类名\r\n\r\n5. 映射配置文件的操作配置（select），id属性的取值必须是dao接口的方法名\r\n\r\n   当我们遵从了第三，四，五点之后，我们在开发中就无须再写dao的实现类。\r\n\r\n### mybatis的入门案例：\r\n\r\n1. 读取配置文件\r\n2. 第二步：创建SqlSessionFactory工厂\r\n3. 创建SqlSession\r\n4. 创建Dao接口的代理对象\r\n5. 执行dao中的方法\r\n6. 释放资源\r\n\r\n\r\n\r\n实体类**User.java**\r\n\r\n接口**UserDao**，一个 **List\u003cUser\u003e findAll()**\r\n\r\n**测试main方法：**\r\n\r\n```Java\r\n//1.读取配置文件\r\nInputStream in = Resources.getResourceAsStream(\"SqlMapConfig.xml\");\r\n//2.创建SqlSessionFactory工厂\r\nSqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();\r\nSqlSessionFactory factory = builder.build(in);\r\n//3.使用工厂生产SqlSession对象\r\nSqlSession session = factory.openSession();\r\n//4.使用SqlSession创建Dao接口的代理对象\r\nUserDao userDao = session.getMapper(UserDao.class);\r\n//5.使用代理对象执行方法\r\nList\u003cUser\u003e users = userDao.findAll();\r\nfor (User user : users) {\r\n    System.out.println(user);\r\n}\r\n//6.释放资源\r\nsession.close();\r\nin.close();\r\n```\r\n\r\n**SqlMapConfig.xml**\r\n\r\n```xml\r\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\r\n\u003c!DOCTYPE configuration\r\n\t\tPUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\r\n\t\t\"http://mybatis.org/dtd/mybatis-3-config.dtd\"\u003e\r\n\u003c!-- mybatis的主配置文件 --\u003e\r\n\u003cconfiguration\u003e\r\n\t\u003c!-- 配置环境 --\u003e\r\n\t\u003cenvironments default=\"mysql\"\u003e\r\n\t\t\u003c!-- 配置mysql环境 --\u003e\r\n\t\t\u003cenvironment id=\"mysql\"\u003e\r\n\t\t\t\u003c!-- 配置事务的类型 --\u003e\r\n\t\t\t\u003ctransactionManager type=\"JDBC\"/\u003e\r\n\t\t\t\u003c!-- 配置数据源（连接池） --\u003e\r\n\t\t\t\u003cdataSource type=\"POOLED\"\u003e\r\n\t\t\t\t\u003c!-- 配置连接数据库的4个基本信息的 --\u003e\r\n\t\t\t\t\u003cproperty name=\"driver\" value=\"com.mysql.jdbc.Driver\"/\u003e\r\n\t\t\t\t\u003cproperty name=\"url\" value=\"jdbc:mysql://localhost:3306/mybatistest\"/\u003e\r\n\t\t\t\t\u003cproperty name=\"username\" value=\"root\"/\u003e\r\n\t\t\t\t\u003cproperty name=\"password\" value=\"root\"/\u003e\r\n\t\t\t\u003c/dataSource\u003e\r\n\t\t\u003c/environment\u003e\r\n\t\u003c/environments\u003e\r\n\r\n\t\u003c!-- 指定映射配置文件的位置，映射配置文件指的是每个dao独立的配置文件 --\u003e\r\n\t\u003cmappers\u003e\r\n\t\t\u003cmapper resource=\"com/yoyling/dao/UserDao.xml\"/\u003e\r\n\t\u003c/mappers\u003e\r\n\u003c/configuration\u003e\r\n```\r\n\r\n**UserDao.xml**\r\n\r\n```xml\r\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\r\n\u003c!DOCTYPE mapper\r\n\t\tPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\r\n\t\t\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\"\u003e\r\n\u003cmapper namespace=\"com.yoyling.dao.UserDao\"\u003e\r\n\t\u003cselect id=\"findAll\" resultType=\"com.yoyling.domain.User\"\u003e\r\n\t\tselect * from user;\r\n\t\u003c/select\u003e\r\n\u003c/mapper\u003e\r\n```\r\n\r\n\r\n\r\n### 注意事项：\r\n\r\n不要忘记在映射配置中告知mybatis要封装到哪个实体类中\r\n\r\n配置的方式：指定实体类的全限定类名\r\n\r\n## 01_02mybatis_annotation\r\n\r\n**mybatis基于注解的入门案例：**\r\n\r\n把UserDao.xml移除，在dao接口的方法上使用@Select注解，并且指定SQL语句。\r\n\r\n同时需要在SqlMapConfig.xml中的mapper配置时，使用class属性指定dao接口的全限定类名。\r\n\r\n```java\r\npublic interface UserDao {\r\n    @Select(\"select * from user\")\r\n    List\u003cUser\u003e findAll();\r\n}\r\n```\r\n\r\n```xml\r\n\u003c!-- SqlMapConfig.xml中的\u003cconfiguration\u003e标签中的\u003cmappers\u003e需要改动 --\u003e\r\n\u003cmappers\u003e\r\n   \u003cmapper class=\"com.yoyling.dao.UserDao\"/\u003e\r\n\u003c/mappers\u003e\r\n```\r\n\r\n**明确：**\r\n\r\n我们在实际开发中，都是越简便越好，所以都是采用不写dao实现类的方式。\r\n\r\n不管使用XML还是注解配置。\r\n\r\n但是Mybatis它是支持写dao实现类的。\r\n\r\n## 01_03mybatis_dao\r\n\r\nMybatis的dao实现类\r\n\r\n## 01_04mybatis_design\r\n\r\n**自定义Mybatis的分析：**\r\n\r\nmybatis在使用代理dao的方式实现增删改查时做什么事呢？\r\n\r\n1. 创建代理对象\r\n2. 在代理对象中调用selectList\r\n\r\n**自定义mybatis能通过入门案例看到类：**\r\n\r\n- class Resources\r\n- class SqlSessionFactoryBuilder\r\n- interface SqlSessionFactory\r\n- interface SqlSession\r\n\r\n## 02_01mybatisCRUD\r\n\r\nUserDao.xml\r\n\r\n```xml\r\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\r\n\u003c!DOCTYPE mapper\r\n\t\tPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\r\n\t\t\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\"\u003e\r\n\u003cmapper namespace=\"com.yoyling.dao.UserDao\"\u003e\r\n\r\n\t\u003c!-- 配置查询结果的列名和实体类的属性名的对应关系 --\u003e\r\n\t\u003cresultMap id=\"userMap\" type=\"user\"\u003e\r\n\t\t\u003c!-- 主键字段对应 --\u003e\r\n\t\t\u003cid property=\"userId\" column=\"id\"/\u003e\r\n\t\t\u003c!-- 非主键字段对应 --\u003e\r\n\t\t\u003cresult property=\"userName\" column=\"username\"/\u003e\r\n\t\t\u003cresult property=\"userAddress\" column=\"address\"/\u003e\r\n\t\t\u003cresult property=\"userSex\" column=\"sex\"/\u003e\r\n\t\t\u003cresult property=\"userBirthday\" column=\"birthday\"/\u003e\r\n\t\u003c/resultMap\u003e\r\n\r\n\t\u003c!-- 查询所有 --\u003e\r\n\t\u003cselect id=\"findAll\" resultMap=\"userMap\"\u003e\r\n\t\t\u003c!--select id as userId,username as userName,address as userAddress,sex as userSex,birthday as userBirthday from user;--\u003e\r\n\t\tselect * from user;\r\n\t\u003c/select\u003e\r\n\r\n\t\u003c!-- 保存用户 --\u003e\r\n\t\u003cinsert id=\"saveUser\" parameterType=\"user\"\u003e\r\n\t\t\u003c!-- 配置插入操作后，获取插入数据的id --\u003e\r\n\t\t\u003cselectKey keyProperty=\"userId\" keyColumn=\"id\" resultType=\"int\" order=\"AFTER\"\u003e\r\n\t\t\tselect last_insert_id();\r\n\t\t\u003c/selectKey\u003e\r\n\t\tinsert into user(username,address,sex,birthday)values(#{userName},#{userAddress},#{userSex},#{userBirthday});\r\n\t\u003c/insert\u003e\r\n\r\n\t\u003c!-- 更新用户 --\u003e\r\n\t\u003cupdate id=\"updateUser\" parameterType=\"user\"\u003e\r\n\t\tupdate user set username=#{userName},address=#{userAddress},sex=#{userSex},birthday=#{userBirthday} where id=#{userId};\r\n\t\u003c/update\u003e\r\n\r\n\t\u003c!-- 删除用户 --\u003e\r\n\t\u003cdelete id=\"deleteUser\" parameterType=\"int\"\u003e\r\n\t\tdelete from user where id = #{uid}\r\n\t\u003c/delete\u003e\r\n\r\n\t\u003c!-- 根据id查询用户 --\u003e\r\n\t\u003cselect id=\"findById\" parameterType=\"int\" resultMap=\"userMap\"\u003e\r\n\t\tselect * from user where id = #{uid}\r\n\t\u003c/select\u003e\r\n\r\n\t\u003c!-- 根据名称模糊查询 --\u003e\r\n\t\u003cselect id=\"findByName\" parameterType=\"String\" resultMap=\"userMap\"\u003e\r\n \t\tselect * from user where username like #{username}\r\n\t\t\u003c!-- select * from user where username like '%${value}%' --\u003e\r\n\t\u003c/select\u003e\r\n\r\n\t\u003c!-- 查询总用户数 --\u003e\r\n\t\u003cselect id=\"findTotal\" resultType=\"int\"\u003e\r\n\t\tselect count(id) from user;\r\n\t\u003c/select\u003e\r\n\r\n\t\u003c!-- 根据queryVo的条件查询用户 --\u003e\r\n\t\u003cselect id=\"findUserByVo\" parameterType=\"com.yoyling.domain.QueryVo\" resultMap=\"userMap\"\u003e\r\n\t\tselect * from user where username like #{user.userName}\r\n\t\u003c/select\u003e\r\n\u003c/mapper\u003e\r\n```\r\n\r\n\r\n\r\nMybatisTest.java\r\n\r\n```java\r\npackage com.yoyling.test;\r\n\r\n/**\r\n * 测试mybatis的crud操作\r\n */\r\npublic class MybatisTest {\r\n\r\n    private InputStream in;\r\n    private SqlSession sqlSession;\r\n    private UserDao userDao;\r\n\r\n    @Before     //用于在测试方法执行之前执行\r\n    public void init() throws Exception {\r\n        in = Resources.getResourceAsStream(\"sqlMapConfig.xml\");\r\n        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);\r\n        sqlSession = factory.openSession();\r\n        userDao = sqlSession.getMapper(UserDao.class);\r\n    }\r\n\r\n    @After     //用于在测试方法执行之后执行\r\n    public void destroy() throws Exception {\r\n        //提交事务\r\n        sqlSession.commit();\r\n\r\n        sqlSession.close();\r\n        in.close();\r\n    }\r\n\r\n    @Test\r\n    public void testFindAll(){\r\n        List\u003cUser\u003e users = userDao.findAll();\r\n        for (User user : users) {\r\n            System.out.println(user);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 测试保存操作\r\n     */\r\n    @Test\r\n    public void testSave() {\r\n        User user = new User();\r\n        user.setUserName(\"yoyling 最后插入\");\r\n        user.setUserAddress(\"福建省厦门市\");\r\n        user.setUserSex(\"男\");\r\n        user.setUserBirthday(new Date());\r\n\r\n        System.out.println(\"保存操作前：\" + user);\r\n        userDao.saveUser(user);\r\n        System.out.println(\"保存操作后：\" + user);\r\n    }\r\n\r\n    /**\r\n     * 测试更新操作\r\n     */\r\n    @Test\r\n    public void testUpdate() {\r\n        User user = new User();\r\n        user.setUserId(50);\r\n        user.setUserName(\"mybatis\");\r\n        user.setUserAddress(\"福建省漳州市\");\r\n        user.setUserSex(\"女\");\r\n        user.setUserBirthday(new Date());\r\n\r\n        userDao.updateUser(user);\r\n    }\r\n\r\n    /**\r\n     * 测试删除操作\r\n     */\r\n    @Test\r\n    public void testDelete() {\r\n        userDao.deleteUser(50);\r\n    }\r\n\r\n    /**\r\n     * 测试查询一个操作\r\n     */\r\n    @Test\r\n    public void testFindOne() {\r\n        User user = userDao.findById(48);\r\n        System.out.println(user);\r\n    }\r\n\r\n    /**\r\n     * 测试模糊查询操作\r\n     */\r\n    @Test\r\n    public void testFindByName() {\r\n        List\u003cUser\u003e users = userDao.findByName(\"%王%\");\r\n//        List\u003cUser\u003e users = userDao.findByName(\"王\");\r\n        for (User user : users) {\r\n            System.out.println(user);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 测试查询总记录条数操作\r\n     */\r\n    @Test\r\n    public void testFindTotal() {\r\n        int count = userDao.findTotal();\r\n        System.out.println(count);\r\n    }\r\n\r\n    /**\r\n     * 测试使用QueryVo作为查询条件\r\n     */\r\n    @Test\r\n    public void testFindByVo() {\r\n        QueryVo vo = new QueryVo();\r\n        User user = new User();\r\n        user.setUserName(\"%王%\");\r\n        vo.setUser(user);\r\n        List\u003cUser\u003e users = userDao.findUserByVo(vo);\r\n        for (User u : users) {\r\n            System.out.println(u);\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n**resultMap**\r\n\r\n配置**查询结果**的列名和实体类的属性名的对应关系\r\n\r\n```xml\r\n\u003cresultMap id=\"userMap\" type=\"user\"\u003e\r\n   \u003c!-- 主键字段对应 --\u003e\r\n   \u003cid property=\"userId\" column=\"id\"/\u003e\r\n   \u003c!-- 非主键字段对应 --\u003e\r\n   \u003cresult property=\"userName\" column=\"username\"/\u003e\r\n   \u003cresult property=\"userAddress\" column=\"address\"/\u003e\r\n   \u003cresult property=\"userSex\" column=\"sex\"/\u003e\r\n   \u003cresult property=\"userBirthday\" column=\"birthday\"/\u003e\r\n\u003c/resultMap\u003e\r\n```\r\n\r\n```xml\r\n\u003c!-- 查询所有 --\u003e\r\n\u003cselect id=\"findAll\" resultMap=\"userMap\"\u003e\r\n```\r\n\r\n\r\n\r\n**SqlMapConfig.xml中的\u003ctypeAliases\u003e**\r\n\r\n**typeAlias**用于配置别名。**type**属性指定的是实体类全限定类名。**alias**属性指定别名，当指定了别名就不再区分大小写。\r\n\r\n```xml\r\n\u003ctypeAliases\u003e\r\n   \u003ctypeAlias type=\"com.yoyling.domain.User\" alias=\"user\"/\u003e\r\n\u003c/typeAliases\u003e\r\n```\r\n\r\n用于指定要配置别名的包，当指定之后该包下的实体类都会注册别名，并且类名就是别名，不再区分大小写。\r\n\r\n```xml\r\n\u003ctypeAliases\u003e\r\n   \u003cpackage name=\"com.yoyling.domain\"/\u003e\r\n\u003c/typeAliases\u003e\r\n```\r\n\r\n```xml\r\n\u003c!-- 保存用户中的parameterType则可以直接写不区分大小写的类名 --\u003e\r\n\u003cinsert id=\"saveUser\" parameterType=\"user\"\u003e\r\n```\r\n\r\n\r\n\r\n**SqlMapConfig.xml中把jdbc连接信息提取到外面的properties文件**\r\n\r\n```xml\r\n\u003cproperties resource=\"jdbcConfig.properties\"/\u003e\r\n\u003cenvironments default=\"mysql\"\u003e\r\n\t\u003cenvironment id=\"mysql\"\u003e\r\n\t\t\u003ctransactionManager type=\"JDBC\"/\u003e\r\n\t\t\u003cdataSource type=\"POOLED\"\u003e\r\n\t\t\t\u003cproperty name=\"driver\" value=\"${jdbc.driver}\"/\u003e\r\n\t\t\t\u003cproperty name=\"url\" value=\"${jdbc.url}\"/\u003e\r\n\t\t\t\u003cproperty name=\"username\" value=\"${jdbc.username}\"/\u003e\r\n\t\t\t\u003cproperty name=\"password\" value=\"${jdbc.password}\"/\u003e\r\n\t\t\u003c/dataSource\u003e\r\n\t\u003c/environment\u003e\r\n\u003c/environments\u003e\r\n```\r\n\r\n**jdbcConfig.properties**\r\n\r\n```properties\r\njdbc.driver = com.mysql.jdbc.Driver\r\njdbc.url = jdbc:mysql://localhost:3306/mybatistest\r\njdbc.username = root\r\njdbc.password = root\r\n```\r\n\r\n## 02_02mybatisDAO\r\n\r\nmybatis也可以自己编写Dao实现或者使用代理Dao实现。\r\n\r\n**UserDaoImpl.java**\r\n\r\n```java\r\npackage com.yoyling.dao.impl;\r\n\r\npublic class UserDaoImpl implements UserDao {\r\n\r\n    private SqlSessionFactory factory;\r\n\r\n    public UserDaoImpl(SqlSessionFactory factory) {\r\n        this.factory = factory;\r\n    }\r\n\r\n    @Override\r\n    public List\u003cUser\u003e findAll() {\r\n        //1.根据factory获取SqlSession对象\r\n        SqlSession session = factory.openSession();\r\n        //2.调用SqlSession中的方法，实现查询列表\r\n        List\u003cUser\u003e users = session.selectList(\"com.yoyling.dao.UserDao.findAll\");//参数就是能获取配置信息的key\r\n        //3.释放资源\r\n        session.close();\r\n        return users;\r\n    }\r\n\r\n    @Override\r\n    public void saveUser(User user) {\r\n        //1.根据factory获取SqlSession对象\r\n        SqlSession session = factory.openSession();\r\n        //2.调用方法实现保存\r\n        session.insert(\"com.yoyling.dao.UserDao.saveUser\",user);\r\n        //3.提交事务\r\n        session.commit();\r\n        //4.释放资源\r\n        session.close();\r\n    }\r\n\r\n    @Override\r\n    public void updateUser(User user) {\r\n        //1.根据factory获取SqlSession对象\r\n        SqlSession session = factory.openSession();\r\n        //2.调用方法实现更新\r\n        session.update(\"com.yoyling.dao.UserDao.updateUser\",user);\r\n        //3.提交事务\r\n        session.commit();\r\n        //4.释放资源\r\n        session.close();\r\n    }\r\n}\r\n```\r\n\r\n**MybatisTest.java**\r\n\r\n```java\r\npackage com.yoyling.test;\r\n\r\n/**\r\n * 测试mybatis的crud操作\r\n */\r\npublic class MybatisTest {\r\n\r\n    private InputStream in;\r\n    private UserDao userDao;\r\n\r\n    @Before     //用于在测试方法执行之前执行\r\n    public void init() throws Exception {\r\n        in = Resources.getResourceAsStream(\"sqlMapConfig.xml\");\r\n        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);\r\n        userDao = new UserDaoImpl(factory);\r\n    }\r\n\r\n    @After     //用于在测试方法执行之后执行\r\n    public void destroy() throws Exception {\r\n        in.close();\r\n    }\r\n\r\n    @Test\r\n    public void testFindAll(){\r\n        List\u003cUser\u003e users = userDao.findAll();\r\n        for (User user : users) {\r\n            System.out.println(user);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 测试保存操作\r\n     */\r\n    @Test\r\n    public void testSave() {\r\n        User user = new User();\r\n        user.setUsername(\"yoyling 最后插入\");\r\n        user.setAddress(\"福建省厦门市\");\r\n        user.setSex(\"男\");\r\n        user.setBirthday(new Date());\r\n\r\n        System.out.println(\"保存操作前：\" + user);\r\n        userDao.saveUser(user);\r\n        System.out.println(\"保存操作后：\" + user);\r\n    }\r\n\r\n    /**\r\n     * 测试更新操作\r\n     */\r\n    @Test\r\n    public void testUpdate() {\r\n        User user = new User();\r\n        user.setId(49);\r\n        user.setUsername(\"mybatis\");\r\n        user.setAddress(\"福建省漳州市\");\r\n        user.setSex(\"女\");\r\n        user.setBirthday(new Date());\r\n\r\n        userDao.updateUser(user);\r\n    }\r\n}\r\n```\r\n\r\n## 03_01datasourceAndTx\r\n\r\n**连接池：**\r\n\r\n* 我们在实际开发中都会使用连接池。\r\n* 因为它可以减少我们获取连接所消耗的时间。\r\n\r\n**mybatis中的连接池：**\r\n\r\n主配置文件SqlMapConfig.xml中的dataSource标签，type属性就是表示采用何种连接池方式。\r\n\r\n\r\n\r\n**type属性的取值：**\r\n\r\n**POOLED ** 采用传统的javax.sql.DataSource规范中的连接池，mybatis中有针对规范的实现。\r\n\r\n**UNPOOLED**  采用传统的获取连接的方式，虽然也实现Javax.sql.DataSource接口，但是并没有使用池的思想。\r\n\r\n**JNDI ** 采用服务器提供的JNDI技术实现，来获取DataSource对象，不同的服务器所能拿到DataSource是不一样。\r\n\r\n\r\n\r\n**mybatis中的事务**\r\n\r\n什么是事务、事务的四大特性ACID、不考虑隔离性会产生的3个问题、解决办法：四种隔离级别\r\n\r\n它是通过sqlsession对象的commit方法和rollback方法实现事务的提交和回滚\r\n\r\n## 03_02dynamicSQL\r\n\r\nMyBatis动态SQL（select查询）常用标签： \u003cwhere\u003e\u003cif\u003e\u003cforeach\u003e\r\n\r\n```xml\r\n\u003c!-- 了解的内容:抽取重复的sql语句 --\u003e\r\n\u003csql id=\"defaultUser\"\u003e\r\n   select * from user\r\n\u003c/sql\u003e\r\n\r\n\u003c!-- 查询所有 --\u003e\r\n\u003cselect id=\"findAll\" resultMap=\"userMap\"\u003e\r\n   \u003cinclude refid=\"defaultUser\"/\u003e\r\n\u003c/select\u003e\r\n\r\n\u003c!-- 根据条件查询\r\n\u003cselect id=\"findUserByCondition\" resultMap=\"userMap\" parameterType=\"user\"\u003e\r\n   select * from user where 1 = 1\r\n   \u003cif test=\"userName != null\"\u003e\r\n      and username = #{userName}\r\n   \u003c/if\u003e\r\n   \u003cif test=\"userSex != null\"\u003e\r\n      and sex = #{userSex}\r\n   \u003c/if\u003e\r\n\u003c/select\u003e --\u003e\r\n\u003cselect id=\"findUserByCondition\" resultMap=\"userMap\" parameterType=\"user\"\u003e\r\n   \u003cinclude refid=\"defaultUser\"/\u003e\r\n   \u003cwhere\u003e\r\n      \u003cif test=\"userName != null\"\u003e\r\n         and username = #{userName}\r\n      \u003c/if\u003e\r\n      \u003cif test=\"userSex != null\"\u003e\r\n         and sex = #{userSex}\r\n      \u003c/if\u003e\r\n   \u003c/where\u003e\r\n\u003c/select\u003e\r\n\r\n\u003c!-- 根据queryvo中提供的id集合查询用户列表 --\u003e\r\n\u003cselect id=\"findUserInIds\" resultMap=\"userMap\" parameterType=\"queryvo\"\u003e\r\n   \u003cinclude refid=\"defaultUser\"/\u003e\r\n   \u003cwhere\u003e\r\n      \u003cif test=\"ids != null and ids.size()\u003e0\"\u003e\r\n         \u003cforeach collection=\"ids\" open=\"and id in (\" close=\")\" item=\"id\" separator=\",\"\u003e\r\n            #{id}\r\n         \u003c/foreach\u003e\r\n      \u003c/if\u003e\r\n   \u003c/where\u003e\r\n\u003c/select\u003e\r\n```\r\n\r\n\r\n\r\n## 03_03one2many\r\n\r\n多表关系操作，添加账户 **account** 表：\r\n\r\n```SQL\r\nDROP TABLE IF EXISTS `account`;\r\n\r\nCREATE TABLE `account` (\r\n  `ID` int(11) NOT NULL COMMENT '编号',\r\n  `UID` int(11) default NULL COMMENT '用户编号',\r\n  `MONEY` double default NULL COMMENT '金额',\r\n  PRIMARY KEY  (`ID`),\r\n  KEY `FK_Reference_8` (`UID`),\r\n  CONSTRAINT `FK_Reference_8` FOREIGN KEY (`UID`) REFERENCES `user` (`id`)\r\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\r\n\r\ninsert  into `account`(`ID`,`UID`,`MONEY`) values (1,46,1000),(2,45,1000),(3,46,2000);\r\n```\r\n\r\n**MyBatis中的多表查询举例：**\r\n\r\n* **一对多(多对一)： **订单和用户\r\n\r\n* **一对一 ：** 一人一个身份证号\r\n\r\n* **多对多： **老师和学生\r\n\r\n以下代码示例：**用户**和**账户**\r\n\r\n* 一个用户有多个账户\r\n\r\n* 一个账户只能属于一个用户\r\n\r\n1.建立两表，用户表、账户表\r\n\r\n* 之间一对多关系用外键关联\r\n\r\n2.建立两实体类，用户类、账户类\r\n\r\n* 让实体类体现出一对多关系\r\n\r\n3.建立两配置文件\r\n\r\n4.实现配置\r\n\r\n* 当我们查询用户时，可以同时得到用户下所包含的账户信息\r\n* 当我们查询账户时，可以同时得到账户的所属用户信息\r\n\r\n### 一对一：\r\n\r\n**第一种关系体现方式：新建AccountUser类**，继承Account，然后加入用户名和地址的属性；在toString()加上super.toString\r\n\r\n```Java\r\npublic class AccountUser extends Account {\r\n\r\n    private String username;\r\n    private String address;\r\n\r\n    public String getUsername() {return username;}\r\n\r\n    public void setUsername(String username) {this.username = username;}\r\n\r\n    public String getAddress() {return address;}\r\n\r\n    public void setAddress(String address) {this.address = address;}\r\n\r\n    @Override\r\n    public String toString() {\r\n        return super.toString()+\"     AccountUser{\" +\r\n                \"username='\" + username + '\\'' +\r\n                \", address='\" + address + '\\'' +\r\n                '}';\r\n    }\r\n}\r\n\r\n\u003c!-- 查询所有账户并且包含用户名和地址信息 --\u003e\r\n\u003cselect id=\"findAllAccount\" resultType=\"accountuser\"\u003e\r\n   select a.*,u.username,u.address from account a,user u where u.id = a.uid;\r\n\u003c/select\u003e\r\n```\r\n\r\n**第二种关系体现方式：从表实体包含主表实体的对象引用**\r\n\r\nAccount.java\r\n\r\n```Java\r\npublic class Account implements Serializable {\r\n    private Integer id;\r\n    private Integer uid;\r\n    private double money;\r\n\r\n    //从表实体应该包含一个主表实体的对象引用\r\n    private User user;\r\n\r\n    public User getUser() {return user;}\r\n    public void setUser(User user) {this.user = user;}\r\n    \r\n    public Integer getId() {return id;}\r\n    public void setId(Integer id) {this.id = id;}\r\n    public Integer getUid() {return uid;}\r\n    public void setUid(Integer uid) {this.uid = uid;}\r\n    public double getMoney() {return money;}\r\n    public void setMoney(double money) {this.money = money;}\r\n\r\n    @Override\r\n    public String toString() {\r\n        return \"Account{\" +\r\n                \"id=\" + id +\r\n                \", uid=\" + uid +\r\n                \", money=\" + money +\r\n                '}';\r\n    }\r\n}\r\n```\r\n\r\nAccountDao.xml\r\n\r\n```xml\r\n\u003c!-- 定义封装account和user的resultMap --\u003e\r\n\u003cresultMap id=\"accountUserMap\" type=\"account\"\u003e\r\n   \u003cid property=\"id\" column=\"aid\"/\u003e\r\n   \u003cresult property=\"uid\" column=\"uid\"/\u003e\r\n   \u003cresult property=\"money\" column=\"money\"/\u003e\r\n   \u003c!-- 一对一的关系映射：配置封装user的内容 --\u003e\r\n   \u003cassociation property=\"user\" column=\"uid\" javaType=\"user\"\u003e\r\n      \u003cid    property=\"id\" column=\"id\"\u003e\u003c/id\u003e\r\n      \u003cresult column=\"username\" property=\"username\"\u003e\u003c/result\u003e\r\n      \u003cresult column=\"address\" property=\"address\"\u003e\u003c/result\u003e\r\n      \u003cresult column=\"sex\" property=\"sex\"\u003e\u003c/result\u003e\r\n      \u003cresult column=\"birthday\" property=\"birthday\"\u003e\u003c/result\u003e\r\n   \u003c/association\u003e\r\n\u003c/resultMap\u003e\r\n\r\n\u003c!-- 查询所有 --\u003e\r\n\u003cselect id=\"findAll\" resultMap=\"accountUserMap\"\u003e\r\n   select u.*,a.id as aid,a.uid,a.money from account a,user u where u.id = a.uid;\r\n\u003c/select\u003e\r\n```\r\n\r\nAccountTest.java\r\n\r\n```java\r\n@Test\r\npublic void testFindAll(){\r\n    List\u003cAccount\u003e users = accountDao.findAll();\r\n    for (Account account : users) {\r\n        System.out.println(account);\r\n        System.out.println(account.getUser());\r\n    }\r\n}\r\n```\r\n\r\n### 一对多：\r\n\r\nUser.java\r\n\r\n```Java\r\npublic class User implements Serializable {\r\n    private Integer id;\r\n    private String username;\r\n    private String sex;\r\n    private String address;\r\n    private Date birthday;\r\n\r\n    //一对多关系映射：主表实体应该包含从表实体的集合引用\r\n    private List\u003cAccount\u003e accounts;\r\n\r\n    public List\u003cAccount\u003e getAccounts() {\r\n        return accounts;\r\n    }\r\n\r\n    public void setAccounts(List\u003cAccount\u003e accounts) {\r\n        this.accounts = accounts;\r\n    }\r\n    ......\r\n}\r\n```\r\n\r\nUserDao.xml\r\n\r\n```xml\r\n\u003c!-- 定义User的resultMap --\u003e\r\n\u003cresultMap id=\"userAccountMap\" type=\"user\"\u003e\r\n   \u003cid    property=\"id\" column=\"id\"/\u003e\r\n   \u003cresult property=\"username\" column=\"username\"/\u003e\r\n   \u003cresult property=\"address\" column=\"address\"/\u003e\r\n   \u003cresult property=\"sex\" column=\"sex\"/\u003e\r\n   \u003cresult property=\"birthday\" column=\"birthday\"/\u003e\r\n   \u003c!-- 配置user对象中accounts集合的映射 --\u003e\r\n   \u003ccollection property=\"accounts\" ofType=\"account\"\u003e\r\n      \u003cid    column=\"aid\" property=\"id\"/\u003e\r\n      \u003cresult column=\"uid\" property=\"uid\"/\u003e\r\n      \u003cresult column=\"money\" property=\"money\"/\u003e\r\n   \u003c/collection\u003e\r\n\u003c/resultMap\u003e\r\n\u003c!-- 查询所有 --\u003e\r\n\u003cselect id=\"findAll\" resultMap=\"userAccountMap\"\u003e\r\n   select * from user u left outer join account a on u.id = a.uid\r\n\u003c/select\u003e\r\n```\r\n\r\nUserTest.java\r\n\r\n```Java\r\n@Test\r\npublic void testFindAll(){\r\n    List\u003cUser\u003e users = userDao.findAll();\r\n    for (User user : users) {\r\n        System.out.println(user);\r\n        System.out.println(user.getAccounts());\r\n    }\r\n}\r\n```\r\n\r\n## 03_04many2many\r\n\r\n### 多对多：\r\n\r\n示例：用户和角色\r\n\r\n一个用户多个角色，一个角色可赋予多个用户\r\n\r\n使用中间表，包含各自主键。在中间表为外键。两实体类各自包含对方一个集合引用。\r\n\r\n数据库新建两个表 **role** 和 **user_role**，为角色表，和用户角色中间表。\r\n\r\n```sql\r\nDROP TABLE IF EXISTS `role`;\r\n\r\nCREATE TABLE `role` (\r\n  `ID` int(11) NOT NULL COMMENT '编号',\r\n  `ROLE_NAME` varchar(30) default NULL COMMENT '角色名称',\r\n  `ROLE_DESC` varchar(60) default NULL COMMENT '角色描述',\r\n  PRIMARY KEY  (`ID`)\r\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\r\n\r\ninsert  into `role`(`ID`,`ROLE_NAME`,`ROLE_DESC`) values (1,'院长','管理整个学院'),(2,'总裁','管理整个公司'),(3,'校长','管理整个学校');\r\n\r\n\r\n\r\nDROP TABLE IF EXISTS `user_role`;\r\n\r\nCREATE TABLE `user_role` (\r\n  `UID` int(11) NOT NULL COMMENT '用户编号',\r\n  `RID` int(11) NOT NULL COMMENT '角色编号',\r\n  PRIMARY KEY  (`UID`,`RID`),\r\n  KEY `FK_Reference_10` (`RID`),\r\n  CONSTRAINT `FK_Reference_10` FOREIGN KEY (`RID`) REFERENCES `role` (`ID`),\r\n  CONSTRAINT `FK_Reference_9` FOREIGN KEY (`UID`) REFERENCES `user` (`id`)\r\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\r\n\r\ninsert  into `user_role`(`UID`,`RID`) values (41,1),(45,1),(41,2);\r\n```\r\n\r\nRole.java\r\n\r\n```java\r\nprivate Integer roleId;\r\nprivate String roleName;\r\nprivate String roleDesc;\r\n\r\n//多对多的关系映射：一个角色可以赋予给多个用户\r\nprivate List\u003cUser\u003e users;\r\n\r\npublic List\u003cUser\u003e getUsers() {return users;}\r\n\r\npublic void setUsers(List\u003cUser\u003e users) {this.users = users;}\r\n```\r\n\r\nRoleDao.xml\r\n\r\n```xml\r\n\u003c!-- 定义role表的ResultMap --\u003e\r\n\u003cresultMap id=\"roleMap\" type=\"role\"\u003e\r\n   \u003cid property=\"roleId\" column=\"id\"/\u003e\r\n   \u003cresult property=\"roleName\" column=\"role_name\"/\u003e\r\n   \u003cresult property=\"roleDesc\" column=\"role_desc\"/\u003e\r\n   \u003ccollection property=\"users\" ofType=\"user\"\u003e\r\n      \u003cid column=\"id\" property=\"id\"/\u003e\r\n      \u003cresult column=\"username\" property=\"username\"/\u003e\r\n      \u003cresult column=\"address\" property=\"address\"/\u003e\r\n      \u003cresult column=\"sex\" property=\"sex\"/\u003e\r\n      \u003cresult column=\"birthday\" property=\"birthday\"/\u003e\r\n   \u003c/collection\u003e\r\n\u003c/resultMap\u003e\r\n\u003c!-- 查询所有 --\u003e\r\n\u003cselect id=\"findAll\" resultMap=\"roleMap\"\u003e\r\n   select u.*,r.id as rid,r.role_name,r.role_desc from role r\r\n   left outer join user_role ur on r.id = ur.rid\r\n   left outer join user u on u.id = ur.uid\r\n\u003c/select\u003e\r\n```\r\n\r\n得到输出结果：\r\n\r\n```shell\r\nRole{roleId=41, roleName='院长', roleDesc='管理整个学院'}\r\n[User{id=41, username='老王', sex='男', address='北京', birthday=Tue Feb 27 17:47:08 CST 2018}]\r\nRole{roleId=45, roleName='院长', roleDesc='管理整个学院'}\r\n[User{id=45, username='老六', sex='男', address='西藏', birthday=Sun Mar 04 12:04:06 CST 2018}]\r\nRole{roleId=null, roleName='校长', roleDesc='管理整个学校'}\r\n```\r\n\r\n------\r\n\r\nUser.java\r\n\r\n```java\r\nprivate Integer id;\r\nprivate String username;\r\nprivate String sex;\r\nprivate String address;\r\nprivate Date birthday;\r\n\r\n//多对多的关系映射：一个用户可以具备多个角色\r\nprivate List\u003cRole\u003e roles;\r\n\r\npublic List\u003cRole\u003e getRoles() {return roles;}\r\n\r\npublic void setRoles(List\u003cRole\u003e roles) {this.roles = roles;}\r\n```\r\n\r\nUserDao.xml\r\n\r\n```xml\r\n\u003c!-- 定义User的resultMap --\u003e\r\n\u003cresultMap id=\"userAccountMap\" type=\"user\"\u003e\r\n   \u003cid    property=\"id\" column=\"id\"/\u003e\r\n   \u003cresult property=\"username\" column=\"username\"/\u003e\r\n   \u003cresult property=\"address\" column=\"address\"/\u003e\r\n   \u003cresult property=\"sex\" column=\"sex\"/\u003e\r\n   \u003cresult property=\"birthday\" column=\"birthday\"/\u003e\r\n   \u003ccollection property=\"roles\" ofType=\"role\"\u003e\r\n      \u003cid property=\"roleId\" column=\"rid\"/\u003e\r\n      \u003cresult property=\"roleName\" column=\"role_name\"/\u003e\r\n      \u003cresult property=\"roleDesc\" column=\"role_desc\"/\u003e\r\n   \u003c/collection\u003e\r\n\u003c/resultMap\u003e\r\n\r\n\u003c!-- 查询所有 --\u003e\r\n\u003cselect id=\"findAll\" resultMap=\"userAccountMap\"\u003e\r\n   select u.*,r.id as rid,r.role_name,r.role_desc from user u\r\n       left outer join user_role ur on u.id = ur.uid\r\n       left outer join role r on r.id = ur.rid\r\n\u003c/select\u003e\r\n```\r\n\r\n测试得到输出：\r\n\r\n```Java\r\n@Test\r\npublic void testFindAll(){\r\n    List\u003cUser\u003e users = userDao.findAll();\r\n    for (User user : users) {\r\n        System.out.println(user);\r\n        System.out.println(user.getRoles());\r\n    }\r\n}\r\n```\r\n\r\n```shell\r\nUser{id=41, username='老王', sex='男', address='北京', birthday=Tue Feb 27 17:47:08 CST 2018}\r\n[Role{roleId=1, roleName='院长', roleDesc='管理整个学院'}, Role{roleId=2, roleName='总裁', roleDesc='管理整个公司'}]\r\nUser{id=42, username='小二王', sex='女', address='福建', birthday=Fri Mar 02 15:09:37 CST 2018}\r\n[]\r\nUser{id=43, username='小二王', sex='女', address='厦门', birthday=Sun Mar 04 11:34:34 CST 2018}\r\n[]\r\nUser{id=45, username='老六', sex='男', address='西藏', birthday=Sun Mar 04 12:04:06 CST 2018}\r\n[Role{roleId=1, roleName='院长', roleDesc='管理整个学院'}]\r\nUser{id=46, username='老王', sex='女', address='新疆', birthday=Wed Mar 07 17:37:26 CST 2018}\r\n[]\r\nUser{id=48, username='小马宝莉', sex='女', address='湖南', birthday=Thu Mar 08 11:44:00 CST 2018}\r\n[]\r\n```\r\n\r\n## 03_05jndi\r\n\r\nSqlMapConfig.xml\r\n\r\n```xml\r\n\u003cenvironments default=\"mysql\"\u003e\r\n   \u003cenvironment id=\"mysql\"\u003e\r\n      \u003ctransactionManager type=\"JDBC\"/\u003e\r\n      \u003cdataSource type=\"JNDI\"\u003e\r\n         \u003cproperty name=\"data_source\" value=\"java:comp/env/jdbc/mybatistest\"/\u003e\r\n      \u003c/dataSource\u003e\r\n   \u003c/environment\u003e\r\n\u003c/environments\u003e\r\n```\r\n\r\nMETA-INF -\u003e context.xml\r\n\r\n```xml\r\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\r\n\u003cContext\u003e\r\n\t\u003cResource \r\n\t\tname=\"jdbc/mybatistest\"\r\n\t\ttype=\"javax.sql.DataSource\"\r\n\t\tauth=\"Container\"\r\n\t\tmaxActive=\"20\"\r\n\t\tmaxWait=\"10000\"\r\n\t\tmaxIdle=\"5\"\r\n\t\tusername=\"root\"\r\n\t\tpassword=\"root\"\r\n\t\tdriverClassName=\"com.mysql.jdbc.Driver\"\r\n\t\turl=\"jdbc:mysql://localhost:3306/mybatistest\"\r\n\t/\u003e\r\n\u003c/Context\u003e\r\n```\r\n\r\nindex.jsp\r\n\r\n```java\r\n\u003c%\r\n   //1.读取配置文件\r\n   InputStream in = Resources.getResourceAsStream(\"SqlMapConfig.xml\");\r\n   //2.创建SqlSessionFactory工厂\r\n   SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();\r\n   SqlSessionFactory factory = builder.build(in);\r\n   //3.使用工厂生产SqlSession对象\r\n   SqlSession sqlSession = factory.openSession();\r\n   //4.使用SqlSession创建Dao接口的代理对象\r\n   UserDao userDao = sqlSession.getMapper(UserDao.class);\r\n   //5.使用代理对象执行方法\r\n   List\u003cUser\u003e users = userDao.findAll();\r\n   for (User user : users) {\r\n      System.out.println(user);\r\n   }\r\n   //6.释放资源\r\n   sqlSession.close();\r\n   in.close();\r\n%\u003e\r\n```\r\n\r\n## 04_01lazy\r\n\r\n**延迟加载：**\r\n\r\n在真正使用数据时才发起查询，不用时不查询。按需加载（懒加载）。\r\n\r\n**立即加载：**\r\n\r\n不管用不用只要一调用方法，马上发起查询。\r\n\r\n**一对多，多对多：通常用延迟加载。**\r\n\r\n**多对一，一对一：通常用立即加载。**\r\n\r\n用的时候调用对方配置文件中的一个配置来实现延迟查询功能。\r\n\r\nAccountDao.xml\r\n\r\n```xml\r\n\u003c!-- 定义封装account和user的resultMap --\u003e\r\n\u003cresultMap id=\"accountUserMap\" type=\"account\"\u003e\r\n   \u003cid property=\"id\" column=\"id\"/\u003e\r\n   \u003cresult property=\"uid\" column=\"uid\"/\u003e\r\n   \u003cresult property=\"money\" column=\"money\"/\u003e\r\n   \u003c!-- 一对一的关系映射：配置封装user的内容\r\n   select属性指定的内容：查询用户的唯一标识。\r\n   column属性指定的内容：用户根据id查询时所需的参数值。\r\n   --\u003e\r\n   \u003cassociation property=\"user\" column=\"uid\" javaType=\"user\" select=\"com.yoyling.dao.UserDao.findById\"/\u003e\r\n\u003c/resultMap\u003e\r\n\u003c!-- 查询所有 --\u003e\r\n\u003cselect id=\"findAll\" resultMap=\"accountUserMap\"\u003e\r\n   select * from account;\r\n\u003c/select\u003e\r\n```\r\n\r\nSqlMapConfig.xml\r\n\r\n```xml\r\n\u003c!-- 配置参数 --\u003e\r\n\u003csettings\u003e\r\n   \u003c!-- 开启Mybatis支持延迟加载 --\u003e\r\n   \u003csetting name=\"lazyLoadingEnabled\" value=\"true\"/\u003e\r\n   \u003csetting name=\"aggressiveLazyLoading\" value=\"false\"/\u003e\r\n\u003c/settings\u003e\r\n```\r\n\r\n## 04_02cache\r\n\r\n**缓存：**减少和数据库的交互次数，提高执行效率。\r\n\r\n经常查询并且不经常改变、数据的正确与否对最终结果影响不大的数据。\r\n\r\n**一级缓存：**\r\n\r\nSqlSession对象的缓存。当我们执行查询时，查询结果会同时存入到SqlSession提供的一区域，结构为map。\r\n\r\n当调用SqlSession的修改，添加，删除，commit()，close()等方法时，就会清空一级缓存。\r\n\r\n```java\r\n@Test\r\npublic void testFirstLevelCache(){\r\n    User user1 = userDao.findById(41);\r\n    System.out.println(user1);\r\n    User user2 = userDao.findById(41);\r\n    System.out.println(user2);\r\n    \r\n    System.out.println(user1==user2);\r\n}\r\n```\r\n\r\n```java\r\n@Test\r\npublic void testFirstLevelCache(){\r\n    User user1 = userDao.findById(41);\r\n    System.out.println(user1);\r\n    \r\n    //再次获取SqlSession对象\r\n    //sqlSession.close();\r\n    //sqlSession = factory.openSession();\r\n    sqlSession.clearCache();\r\n    \r\n    userDao = sqlSession.getMapper(UserDao.class);\r\n    \r\n    User user2 = userDao.findById(41);\r\n    System.out.println(user2);\r\n    System.out.println(user1==user2);\r\n}\r\n```\r\n\r\n**二级缓存：**\r\n\r\nMybatis中SqlSessionFactory对象的缓存，由同一个SqlSessionFactory对象创建的SqlSession共享其缓存。\r\n\r\n二级缓存存放的内容是数据不是对象，因此前后不是同一个对象。\r\n\r\n**步骤：**\r\n\r\n1. 让Mybatis框架支持二级缓存（在SqlMapConfig.xml中配置）\r\n2. 让当前的映射文件支持二级缓存（在UserDao.xml中配置）\r\n3. 让当前的操作支持二级缓存（在select标签中配置）\r\n\r\nSqlMapConfig.xml\r\n\r\n```xml\r\n\u003csettings\u003e\r\n   \u003csetting name=\"cacheEnabled\" value=\"true\"/\u003e\r\n\u003c/settings\u003e\r\n```\r\n\r\nUserDao.xml\r\n\r\n```xml\r\n\u003c!-- 开启user支持二级缓存 --\u003e\r\n\u003ccache/\u003e\r\n\r\n\u003c!-- 根据id查询用户 --\u003e\r\n\u003cselect id=\"findById\" parameterType=\"int\" resultType=\"user\" useCache=\"true\"\u003e\r\n   select * from user where id = #{uid}\r\n\u003c/select\u003e\r\n```\r\n\r\n## 04_03annotation_mybatis\r\n\r\nUserDao.java\r\n\r\n```java\r\npackage com.yoyling.dao;\r\n\r\n/**\r\n * CRUD四个注解: @Select @Insert @Update @Delete\r\n */\r\npublic interface UserDao {\r\n\r\n\t/**\r\n\t * 查询所有用户\r\n\t * @return\r\n\t */\r\n\t@Select(\"select * from user\")\r\n\tList\u003cUser\u003e findAll();\r\n\r\n\t/**\r\n\t * 保存用户\r\n\t * @param user\r\n\t */\r\n\t@Insert(\"insert into user(username,address,sex,birthday)values(#{username},#{address},#{sex},#{birthday})\")\r\n\tvoid saveUser(User user);\r\n\r\n\t/**\r\n\t * 更新用户\r\n\t * @param user\r\n\t */\r\n\t@Update(\"update user set username = #{username},address = #{address},sex = #{sex},birthday = #{birthday} where id = #{id}\")\r\n\tvoid updateUser(User user);\r\n\r\n\t/**\r\n\t * 删除用户\r\n\t * @param userId\r\n\t */\r\n\t@Delete(\"delete from user where id = #{id}\")\r\n\tvoid deleteUser(Integer userId);\r\n\r\n\t/**\r\n\t * 根据id查询用户\r\n\t * @param userId\r\n\t * @return\r\n\t */\r\n\t@Select(\"select * from user where id = #{id}\")\r\n\tUser findById(Integer userId);\r\n\r\n\t/**\r\n\t * 根据用户名称模糊查询\r\n\t * @param userName\r\n\t * @return\r\n\t */\r\n\t//@Select(\"select * from user where username like #{username}\")\r\n\t@Select(\"select * from user where username like '%${value}%'\")\r\n\tList\u003cUser\u003e findUserByName(String userName);\r\n\r\n\t/**\r\n\t * 查询总用户数\r\n\t * @return\r\n\t */\r\n\t@Select(\"select count(*) from user\")\r\n\tint findTotalUser();\r\n}\r\n```\r\n\r\n## 04_04annoOne2Many\r\n\r\n**实体属性和数据库表列名的对应：**\r\n\r\nUserDao.java\r\n\r\n```java\r\n/**\r\n * 查询所有用户\r\n * @return\r\n */\r\n@Select(\"select * from user\")\r\n@Results(id=\"userMap\",value={\r\n      @Result(id = true,column = \"id\",property = \"userId\"),\r\n      @Result(column = \"username\",property = \"userName\"),\r\n      @Result(column = \"address\",property = \"userAddress\"),\r\n      @Result(column = \"sex\",property = \"userSex\"),\r\n      @Result(column = \"birthday\",property = \"userBirthday\")\r\n})\r\nList\u003cUser\u003e findAll();\r\n/**\r\n * 根据id查询用户\r\n * @param userId\r\n * @return\r\n */\r\n@Select(\"select * from user where id = #{id}\")\r\n@ResultMap(\"userMap\")\r\nUser findById(Integer userId);\r\n```\r\n\r\nAccount.java\r\n\r\n```java\r\nprivate Integer id;\r\nprivate Integer uid;\r\nprivate Double money;\r\n\r\n//多对一（Mybatis中称为一对一）的映射：一个账户只能属于一个用户\r\nprivate User user;\r\n\r\npublic User getUser() {return user;}\r\n\r\npublic void setUser(User user) {this.user = user;}\r\n```\r\n\r\nAccoundDao.java\r\n\r\n```java\r\n/**\r\n * 查询所有账户，并且获取每个账户所属的用户信息\r\n * @return\r\n */\r\n@Select(\"select * from account\")\r\n@Results(id = \"accountMap\",value = {\r\n      @Result(id = true,column = \"id\",property = \"id\"),\r\n      @Result(column = \"uid\",property = \"uid\"),\r\n      @Result(column = \"money\",property = \"money\"),\r\n      @Result(property = \"user\",column = \"uid\",one = @One(select = \"com.yoyling.dao.UserDao.findById\",fetchType = FetchType.EAGER))\r\n})\r\nList\u003cAccount\u003e findAll();\r\n```\r\n\r\n**一对多：**\r\n\r\nUser.java\r\n\r\n```java\r\n//一对多关系映射：一个用户对应多个账户\r\nprivate List\u003cAccount\u003e accounts;\r\n```\r\n\r\nAccountDao.java\r\n\r\n```java\r\n/**\r\n * 根据用户id查询账户信息\r\n * @param userId\r\n * @return\r\n */\r\n@Select(\"select * from account where uid = #{userId}\")\r\nList\u003cAccount\u003e findAccountByUid(Integer userId);\r\n```\r\n\r\nUserDao.java\r\n\r\n```java\r\n/**\r\n * 查询所有用户\r\n * @return\r\n */\r\n@Select(\"select * from user\")\r\n@Results(id=\"userMap\",value={\r\n      @Result(id = true,column = \"id\",property = \"userId\"),\r\n      @Result(column = \"username\",property = \"userName\"),\r\n      @Result(column = \"address\",property = \"userAddress\"),\r\n      @Result(column = \"sex\",property = \"userSex\"),\r\n      @Result(column = \"birthday\",property = \"userBirthday\"),\r\n      @Result(property = \"accounts\",column = \"id\",many = @Many(select = \"com.yoyling.dao.AccountDao.findAccountByUid\",fetchType = FetchType.LAZY))\r\n\r\n})\r\nList\u003cUser\u003e findAll();\r\n```\r\n\r\n**注解开启二级缓存：**\r\n\r\nUserDao.java\r\n\r\n```java\r\n@CacheNamespace(blocking = true)\r\npublic interface UserDao {...}\r\n```\r\n\r\nSqlMapConfig.xml\r\n\r\n```xml\r\n\u003c!-- 配置开启二级缓存 --\u003e\r\n\u003csettings\u003e\r\n   \u003csetting name=\"cacheEnabled\" value=\"true\"/\u003e\r\n\u003c/settings\u003e\r\n```\r\n\r\nSecondLevelCacheTest.java\r\n\r\n```java\r\n@Test\r\npublic void testFindOne() {\r\n   SqlSession session = factory.openSession();\r\n   UserDao userDao = session.getMapper(UserDao.class);\r\n   User user = userDao.findById(41);\r\n   System.out.println(user);\r\n   session.close();//释放一级缓存\r\n\r\n   SqlSession session1 = factory.openSession();//再次打开session\r\n   UserDao userDao1 = session1.getMapper(UserDao.class);\r\n   User user1 = userDao1.findById(41);\r\n   System.out.println(user1);\r\n   session1.close();\r\n}\r\n```\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frawchen%2Fmybatis-study","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frawchen%2Fmybatis-study","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frawchen%2Fmybatis-study/lists"}