刚开始学习MyBatis的知识要点
Mybatis第一天
mybatis的基础知识
课程安排:
mybatis和springmvc通过订单商品 案例驱动
第一天:基础知识(重点,内容量多)
对原生态jdbc程序(单独使用jdbc开发)问题总结
mybatis框架原理 (掌握)
mybatis入门程序
用户的增、删、改、查
mybatis开发dao两种方法:
原始dao开发方法(程序需要编写dao接口和dao实现类)(掌握)
mybaits的mapper接口(相当于dao接口)代理开发方法(掌握)
mybatis配置文件SqlMapConfig.xml
mybatis核心:
mybatis输入映射(掌握)
mybatis输出映射(掌握)
mybatis的动态sql(掌握)
第二天:高级知识
订单商品数据模型分析
高级结果集映射(一对一、一对多、多对多)
mybatis延迟加载
mybatis查询缓存(一级缓存、二级缓存)
mybaits和spring进行整合(掌握)
mybatis逆向工程
一、对原生态jdbc程序中问题总结
1、数据库连接,使用时就创建,不使用立即释放,对数据库进行频繁连接开启和关闭,造成数据库资源浪费,影响 数据库性能。
设想:使用数据库连接池管理数据库连接。
2、将sql语句硬编码到java代码中,如果sql 语句修改,需要重新编译java代码,不利于系统维护。
设想:将sql语句配置在xml配置文件中,即使sql变化,不需要对java代码进行重新编译。
3、向preparedStatement中设置参数,对占位符号位置和设置参数值,硬编码在java代码中,不利于系统维护。
设想:将sql语句及占位符号和参数全部配置在xml中。
4、从resutSet中遍历结果集数据时,存在硬编码,将获取表的字段进行硬编码,不利于系统维护。
设想:将查询的结果集,自动映射成java对象。
二、Mybatis是什么?
mybatis是一个持久层的框架,是apache下的顶级项目。
mybatis托管到goolecode下,再后来托管到github下(https://github.com/mybatis/mybatis-3/releases)。
mybatis让程序将主要精力放在sql上,通过mybatis提供的映射方式,自由灵活生成(半自动化,大部分需要程序员编写sql)满足需要sql语句。
mybatis可以将向 preparedStatement中的输入参数自动进行输入映射,将查询结果集灵活映射成java对象。(输出映射)
三、Mybatis框架原理图
四、Mybatis入门程序
运行环境:JDK1.8、Eclipse JavaEE Oxygen、MySQL5.5、Navicat for MySQL、Tomcat7、8(两者都有)
Mybatis运行环境(jar包):mybatis-3.2.7.jar
下载链接:https://github.com/mybatis/mybatis-3/releases
数据库名称:mybatis_day04
log4j.properties:
需要使用的jar包:
SqlMapConfig.xml:配置mybatis的运行环境、数据源、事务等。
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE configuration 3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-config.dtd"> 5 <!-- 配置mybatis的运行环境,数据源,事务等 --> 6 <configuration> 7 <!-- 和spring整合后environments配置将废除 --> 8 <environments default="development"> 9 <environment id="development"> 10 <!-- 使用jdbc事务管理,事务控制由mybatis --> 11 <transactionManager type="JDBC"/> 12 <!-- 数据库连接池,由 mybatis管理--> 13 <dataSource type="POOLED"> 14 <property name="driver" value="com.mysql.jdbc.Driver"/> 15 <property name="url" value="jdbc:mysql://localhost:3306/mybatis_day04?characterEncoding=utf-8"/> 16 <property name="username" value="root"/> 17 <property name="password" value="dielianhua"/> 18 </dataSource> 19 </environment> 20 </environments> 21 </configuration>
创建PO类
1 package com.cn.mybatis.po; 2 3 import java.io.Serializable; 4 import java.util.Date; 5 import java.util.List; 6 7 /** 8 * 创建po类 9 * @author 葛云霞 10 * 为了将缓存数据取出执行反序列化操作,因为二级缓存数据存储介质多种多样,不一样在内存。 11 */ 12 public class User implements Serializable{ 13 14 /*属性名和数据库表的字段对应*/ 15 private int id; 16 private String username; 17 private String sex; 18 private Date birthday; 19 private String address; 20 private List<Orders> ordersList; 21 22 public List<Orders> getOrdersList() { 23 return ordersList; 24 } 25 public void setOrdersList(List<Orders> ordersList) { 26 this.ordersList = ordersList; 27 } 28 public int getId() { 29 return id; 30 } 31 public void setId(int id) { 32 this.id = id; 33 } 34 public String getUsername() { 35 return username; 36 } 37 public void setUsername(String username) { 38 this.username = username; 39 } 40 public String getSex() { 41 return sex; 42 } 43 public void setSex(String sex) { 44 this.sex = sex; 45 } 46 public Date getBirthday() { 47 return birthday; 48 } 49 public void setBirthday(Date birthday) { 50 this.birthday = birthday; 51 } 52 public String getAddress() { 53 return address; 54 } 55 public void setAddress(String address) { 56 this.address = address; 57 } 58 @Override 59 public String toString() { 60 return "User [id=" + id + ", username=" + username + ", sex=" + sex + ", birthday=" + birthday + ", address=" 61 + address + "]"; 62 } 63 }
Dao层方法编写
Dao层实现接口类DaoImpl
1 package com.cn.mybatis.dao.impl; 2 3 import org.apache.ibatis.session.SqlSession; 4 import org.apache.ibatis.session.SqlSessionFactory; 5 6 import com.cn.mybatis.dao.UserDao; 7 import com.cn.mybatis.po.User; 8 9 public class UserDaoImpl implements UserDao{ 10 11 //需要向dao实现类中注入sqlSessionFactory 12 //这里通过构造方法注入 13 private SqlSessionFactory sqlSessionFactory; 14 public UserDaoImpl(SqlSessionFactory sqlSessionFactory) { 15 this.sqlSessionFactory = sqlSessionFactory; 16 } 17 18 @Override 19 public User findUserById(int id) throws Exception { 20 SqlSession sqlSession = sqlSessionFactory.openSession(); 21 User user = sqlSession.selectOne("test.findUserById",id); 22 //释放资源 23 sqlSession.close(); 24 return user; 25 } 26 27 @Override 28 public void insertUser(User user) throws Exception { 29 SqlSession sqlSession = sqlSessionFactory.openSession(); 30 //执行插入操作 31 sqlSession.insert("test.insertUser", user); 32 //提交事务 33 sqlSession.commit(); 34 //释放资源 35 sqlSession.close(); 36 } 37 38 @Override 39 public void deleteUser(int id) throws Exception { 40 SqlSession sqlSession = sqlSessionFactory.openSession(); 41 //执行插入操作 42 sqlSession.delete("test.deleteUser", id); 43 //提交事务 44 sqlSession.commit(); 45 //释放资源 46 sqlSession.close(); 47 } 48 49 }
映射文件User.xml
映射文件命名:
User.xml(原始ibatis命名),mapper代理开发映射文件名称叫XXXMapper.xml,比如:UserMapper.xml、ItemsMapper.xml
在映射文件中配置sql语句。
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 <!-- 配置mybatis的映射文件 --> 6 <!-- 映射文件命名:User.xml(原始ibatis命名),mapper代理开发映射文件名称叫xxxMapper.xml 7 比如UserMapper.xml,比如:UserMapper.xml、ItemsMapper.xml 在映射文件中配置sql语句 --> 8 <!-- namespace命名空间,作用就是对sql进行分类化管理,理解sql隔离 9 注意:使用mapper代理方法开发,namespace有特殊重要的作用 --> 10 <mapper namespace="test"> 11 <!-- 在映射文件中配置很多sql语句 --> 12 <!-- 需求:通过id查询用户表的记录 --> 13 <!-- 通过select执行数据库查询id:标识映射文件中的sql 将sql语句封装到mappedstatement对象中, 14 所有将id称为statement的id parameterType:指定输入参数的类型,这里指定int型 15 #{}表示一个占位符号 #{id}:其中的id表示接收输入的参数,参数名称就是id 16 如果输入参数是简单类型,#{}中的参数名可以任意,可以value或其他名称 17 resultType:指定sql输出结果的所映射的java对象类型,select指定resultType表示将单条记录映射成的java对象--> 18 <!-- 配置别名之后,resultType属性值可以简写 --> 19 <select id="findUserById" parameterType="int" resultType="user"> 20 select * from user where id=#{value} 21 </select> 22 <!--根据用户名名称模糊查询用户信息,可能返回多条resultType:指定就是单条记录所映射的java对象类型 23 ${}:表示拼接sql串,将接收到参数的内容不加任何修饰拼接在sql中,引起sql注入 24 ${value}:接收输入参数类型的内容,如果传入类型是简单类型,${}中只能使用value --> 25 <select id="findUserByName" parameterType="java.lang.String" resultType="com.cn.mybatis.po.User"> 26 select * from user where username like '%${value}%' 27 </select> 28 <!--在User.xml中配置添加用户的statement --> 29 <!-- 添加用户 parameterType:指定输入参数类型是pojo(包括用户信息) 30 #{}中指定pojo的属性名,接收到pojo对象的属性值,mybatis通过ognl获取对象的属性值 --> 31 <insert id="insertUser" parameterType="com.cn.mybatis.po.User"> 32 <!-- 自增主键返回 --> 33 <!-- mysql自增主键,执行insert提交之前自动生成一个自增主键 34 通过mysql函数获取到刚插入记录的自增主键; 35 LAST_INSERT_ID() 是insert之后调用此函数 36 修改insertUser定义;--> 37 <!-- 将插入的数据的主键返回,返回到user对象中 38 SELECT LAST_INSERT_ID():得到刚insert进去记录的主键值,只适用于自增主键 39 keyProperty:将查询到主键值设置到parameterType指定的对象的哪个属性 40 Order:SELECT LAST_INSERT_ID()执行顺序,相对于insert语句来说它的执行顺序 41 resultType:指定SELECT LAST_INSERT_ID()的结果类型 --> 42 <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer"> 43 SELECT LAST_INSERT_ID() 44 </selectKey> 45 insert into user(username,birthday,sex,address) value(#{username},#{birthday},#{sex},#{address}) 46 </insert> 47 <!-- 非自增主键返回使用uuid() 48 使用mysql的uuid()函数生成主键,需要修改表中id字段类型为String,长度设置成35位。 49 执行思路:先通过uuid()查询到主键,将主键输入到sql语句中, 50 执行到uuid()语句顺序相对于insert语句之前执行 --> 51 <!-- 使用mysql的uuid()生成主键 52 执行过程: 先通过uuid()查询到主键,将主键设置到user对象的id属性中 53 其次在insert执行时,从user对象中取出id属性值--> 54 <!-- <insert id="insertUser" parameterType="com.cn.mybatis.po.User"> 55 <selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String"> 56 SELECT uuid() 57 </selectKey> 58 insert into user(id,username,birthday,sex,address) value(#{id},#{username},#{birthday},#{sex},#{address}) 59 </insert> --> 60 <!-- 删除用户 根据id删除用户,需要输入id值 --> 61 <delete id="deleteUser" parameterType="java.lang.Integer"> 62 delete from user where id=#{id} 63 </delete> 64 <!-- 更新用户 根据id更新用户 65 分析:需要传入用户的id 需要传入用户的更新信息 66 parameterType指定user对象,包括id和更新信息,注意:id必须存在 67 #{id}:从输入user对象中获取id属性值 --> 68 <update id="updateUser" parameterType="com.cn.mybatis.po.User"> 69 update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id} 70 </update> 71 <!-- 总结 :1.parameterType 在映射文件中通过parameterType指定输入参数的类型 72 2.resultType 在映射文件中通过resultType指定输出结果的类型 73 3.#{} 和 ${} 74 #{}表示一个占位符号,#{}接收输入参数,类型可以是简单类型,pojo,hashmap 75 如果接收简单类型,#{}中可以写成value或其他名称 76 #{}接收pojo对象值,通过ognl读取对象中的属性值,通过属性.属性.属性的方式获取对象属性值 77 78 ${}表示一个拼接符号,会引起sql注入,所以不建议使用${} 79 ${}接收输入参数,类型可以是简单类型,pojo,hashmap 80 如果接收简单类型,${}中只能写成value 81 ${}接收pojo对象值,通过ognl读取对象中的属性值,通过属性.属性.属性...的方式获取对象属性值 82 --> 83 </mapper>
在SqlMapConfig.xml加载映射文件
1 <mappers> 2 <mapper resource="User.xml"/> 3 </mappers>
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE configuration 3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-config.dtd"> 5 <!-- SqlMapConfig.xml 6 mybatis的全局配置文件SqlMapConfig.xml,配置内容如下: 7 properties(属性) settings(全局配置参数) 8 typeAliases(类型别名) typeHandles(类型处理器) 9 objectFactory(对象工厂) plugins(插件) 10 environments(环境集合属性对象) 11 environment(环境子属性对象) 12 transactionManager(事务管理) 13 dataSource(数据源) 14 mappers(映射器)--> 15 <!-- 配置mybatis的运行环境,数据源,事务等 --> 16 <configuration> 17 <!--加载属性文件 --> 18 <properties resource="db.properties"> 19 <!-- properties中还可以配置一些属性名和属性值 --> 20 <!-- <property name="jdbc.driver" value=""/> --> 21 </properties> 22 23 <!-- mybatis默认没有开启延迟加载,需要在SqlMapConfig.xml中setting配置。 24 在mybatis核心配置文件中配置:lazyLoadingEnabled、aggressiveLazyLoading --> 25 <!-- 全局配置参数,需要时再设置 --> 26 <settings> 27 <!-- 打开延迟加载的开关 --> 28 <setting name="lazyLoadingEnabled" value="true"/> 29 <!-- 将积极加载改为消极加载即按需要加载 --> 30 <setting name="aggressiveLazyLoading" value="false"/> 31 <!-- 设置二级缓存的总开关 --> 32 <setting name="cacheEnabled" value="true"/> 33 </settings> 34 35 <!-- typeAliases(别名)重点 36 在mapper.xml中,定义很多的statement,statement需要parameterType指定输入参数的类型、需要resultType指定输出结果的映射类型。 37 如果在指定类型时输入类型全路径,不方便进行开发,可以针对parameterType或resultType指定的类型定义一些别名,在mapper.xml中通过 38 别名定义,方便开发。 39 --> 40 <!--别名定义 --> 41 <typeAliases> 42 <!-- 针对单个别名定义 43 type:类型的路径 44 alias:别名 --> 45 <!-- <typeAlias type="com.cn.mybatis.po.User" alias="user"/> --> 46 <!-- 批量别名定义 47 指定包名,mybatis自动扫描包中的po类,自动定义别名,别名就是类名(首字母大写小写都可以) --> 48 <package name="com.cn.mybatis.po"/> 49 </typeAliases> 50 <!-- 和spring整合后environments配置将废除 --> 51 <environments default="development"> 52 <environment id="development"> 53 <!-- 使用jdbc事务管理,事务控制由mybatis --> 54 <transactionManager type="JDBC"/> 55 <!-- 数据库连接池,由 mybatis管理--> 56 <dataSource type="POOLED"> 57 <!-- <property name="driver" value="com.mysql.jdbc.Driver"/> 58 <property name="url" value="jdbc:mysql://localhost:3306/mybatis_day04?characterEncoding=utf-8"/> 59 <property name="username" value="root"/> 60 <property name="password" value="dielianhua"/> --> 61 <!-- properties特性: 62 注意:MyBatis将按照下面的顺序来加载属性: 63 在properties元素体内定义的属性首先被读取 64 然后会读取properties元素中resource或url加载的属性,它会覆盖已读取的同名属性。 65 最后读取parameterType传递的属性,它会覆盖已读取的同名属性。 --> 66 <!-- 建议:不要在properties元素体内添加任何属性值,只将属性值定义在properties文件中。 67 在properties文件中定义属性名要有一定的特殊性,如XXXX.XXXX.XXXX --> 68 <!-- settings:全局参数配置 69 mybatis框架在运行时可以调整一些运行参数。 70 比如:开启二级缓存、开启延迟加载。 71 全局参数将会影响mybatis的运行行为。 72 详细参见“学习资料/mybatis-settings.xlsx”文件 --> 73 <property name="driver" value="${jdbc.driver}"/> 74 <property name="url" value="${jdbc.url}"/> 75 <property name="username" value="${jdbc.username}"/> 76 <property name="password" value="${jdbc.password}"/> 77 </dataSource> 78 </environment> 79 </environments> 80 <!-- 加载映射文件 --> 81 <mappers> 82 <mapper resource="User.xml"/> 83 <!-- 通过resource方法一次加载一个映射文件 --> 84 <!-- <mapper resource="UserMapper.xml"/> --> 85 <!-- 通过mapper接口加载单个映射文件 86 遵循一些规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在一个目录中 87 上边规范的前提是:使用的是mapper代理方法 --> 88 <!-- <mapper class="com.cn.mybatis.mapper.UserMapper"/> --> 89 <!-- 批量加载mapper 90 指定mapper接口的包名,mybatis自动扫描包下边所有mapper接口进行加载 91 遵循一些规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在一个目录 中 92 上边规范的前提是:使用的是mapper代理方法 93 --> 94 <package name="com.cn.mybatis.mapper"/> 95 </mappers> 96 </configuration> 97 <!-- mybatis和hibernate本质区别和应用场景 98 hibernate:是一个标准orm框架(对象关系映射)。入门门槛较高的,不需要程序写sql。sql语句自动生成了。 99 对sql语句进行优化,修改比较困难的。 100 应用场景:适用与需求变化不多的中小型项目,比如:后台管理系统,erp,orm,oa 101 mybatis:专注是sql(本身需要程序员自己编写sql语句,sql修改优化比较方便。 102 mybatis是一个不完全的orm框架,虽然程序员自己写sql,mybatis也可以实现映射(输入映射,输出映射)) 103 应用场景:适用与需求变化较多的项目,比如:互联网项目 -->
测试类方法编写:
1 //添加用户信息测试 2 @Test 3 public void insertUserTest() throws Exception { 4 //mybatis配置文件 5 String resource = "SqlMapConfig.xml"; 6 //得到配置流文件 7 InputStream inputStream = Resources.getResourceAsStream(resource); 8 //创建会话工厂,传入mybatis的配置文件信息 9 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 10 //通过工厂得到SqlSession 11 SqlSession sqlSession = sqlSessionFactory.openSession(); 12 //插入用户对象 13 User user = new User(); 14 user.setUsername("丽丽"); 15 user.setBirthday(new Date()); 16 user.setSex("女"); 17 user.setAddress("丰城"); 18 //list中的user和映射文件中resultType所指定的类型一致 19 sqlSession.insert("test.insertUser",user); 20 //提交事务 21 sqlSession.commit(); 22 //获取用户信息主键 23 System.out.println(user.getId()); 24 //关闭会话 25 sqlSession.close(); 26 }
1 // 更新用户测试 2 @Test 3 public void updateUserTest() throws Exception { 4 // mybatis配置文件 5 String resource = "SqlMapConfig.xml"; 6 // 得到配置流文件 7 InputStream inputStream = Resources.getResourceAsStream(resource); 8 // 创建会话工厂,传入mybatis的配置文件信息 9 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 10 // 通过工厂得到SqlSession 11 SqlSession sqlSession = sqlSessionFactory.openSession(); 12 //更新用户信息 13 User user = new User(); 14 //必须设置id 15 user.setId(30); 16 user.setUsername("花花"); 17 user.setBirthday(new Date()); 18 user.setSex("女"); 19 user.setAddress("深圳"); 20 sqlSession.update("test.updateUser", user); 21 // 提交事务 22 sqlSession.commit(); 23 // 关闭会话 24 sqlSession.close(); 25 }