mybatis学习第(一)天
课程安排:
Mybatis和springMVC通过订单商品案例驱动
第一天:基础知识(重点,内容量多)
对原生态jdbc程序(单独使用jdbc开发)问题总结
Mybatis框架原理
Mybatis的入门程序
用户的增、删、改、查
Mybatis开发dao的两种方法:
原始dao开发(程序编写dao接口和dao实现类)
Mybatis的mapper接口(相当于dao接口),代理开发方法
Mybatis的配置文件sqlMapConfig.xml
Mybatis核心:
Mybatis输入映射
Mybatis输出映射
Mybatis的动态sql
1对原声态jdbc程序中问题总结:
1.1 环境 Java环境:jdk1.7.0 开发环境:myeclipes9 数据库环境:mysql5.6 1.2 jdb程序 使用jdbc查询mysql数据库用户表的记录 1.2 问题总结 1.2.1 数据库连接,使用时就创建,不使用时就立即释放,对数据库进行频繁连接开启和关闭,造成数据库资源浪费,影响了数据库性能 解决方案:使用数据库连接池管理我们的连接 1.2.2 将sql语句硬编码到java代码中,如果sql语句需要修改,需要重新编码java代码,不利于系统的维护 设想:将sql语句配置在xml配置文件中,即使sql变化,不需要对java代码重新编译 1.2.3 对preparedStatement中设置参数,对占位符位置和设置参数值,硬编码在java代码中,不利用系统维护 设想:将SQL语句以及占位符参数全部配置在xml中 1.2.4 从resultSet中遍历结果集数据时,存在硬编码,将获取表的字段进行硬编码,不利于维护 设想:将查询的结果集自动映射成java对象
2、mybatis框架简介
Mybatis是什么?
Mybatis是一个持久层的框架,是apache下的顶级项目
Mybatis让程序将主要精力放在sql上,通过mybatis提供的映射方式,自由灵活生成(半自动化,大部分需要程序员编写sql),需要满足sql语句
Mybatis可以将向preparedStatement的输入参数自动映射(输入映射),可以将我们的查询结果集灵活映射出java对象(输出映射)
3、入门程序
根据用户id(主键)查询用户信息
根据用户名模糊查询用户
更新用户
增加用户
删除用户
3.1环境
Log4j.properties:
工程结构:
sqlMapConfig
配置mybatis的运行环境,数据源,事务等
根据用户id查询用户信息
映射文件
映射文件命名:
User.xml(原始ibatis命名),mapper代理开发的映射文件叫XXXMapper.xml
UserMapper.xml
在映射文件中配置sql语句。
User.java
在sqlMapConfig中加载配置文件:
程序编写:
根据用户名称模糊查询用户信息
映射文件:
使用User.xml添加
程序编写:
添加用户
映射文件
在User.xml中配置添加用户的statement
注意这里的sql不能加分号
程序代码
自增主键返回
Mysql自增主键,执行insert提交之前自动生成一个自增主键
通过mysql函数获取到刚入记录的自增主键
LAST_INSERT_ID()
是在insert之后
非自增主键返回(使用uuid())
使用mysql的uuid()函数生成主键,需要修改表中id属性为String,长度设置为35位
执行思路:
先通过uuid()查询到主键,将主键输入到sql语句中
执行uuid()语句顺序相对于insert之前
使用oracle的序列生成主键
<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
SELECT 序列名.nextval()
</selectKey>
insert into user(id,username,birthday,sex,address) value(#{id},#{username},#{birthday},#{sex},#{address})
删除用户
映射文件:
程序代码:
更新用户
映射文件:
程序代码:
总结
parameterType和resultType
ParameterType:在映射文件中通过parameterType指定输入参数类型
resultType:在映射文件中通过resultType指定输出单条记录类型
#{}和${}
#{}表示一个占位符号,接受输入参数,简单类型,pojo,hashMap。
如果接受简单类型,#{}可以写成value或其他名称。
#{}接受pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性…的方式获取对象属性值
${}表示一个拼接符号,会引起sql注入,所以不建议使用
${}表示一个占位符号,接受输入参数,简单类型,pojo,hashMap。
${}接受pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性…的方式获取对象属性值
selectOne和selectList
selectOne表示查询出一条记录进行映射。如果使用selectOne可以实现使用selectList也可以实现(list中只有一个对象)。
SelectList表示查询出一个列表(多条记录)进行映射 。如果使用selectList查询多条记录,不能使用selectOne。
org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3
mybatis和hibernate的本质区别和应用场景
hibernate:一个标准的ORM框架(对象关系映射)入门门槛较高。不需要程序员写sql,sql自动生成了。
对sql语句进行优化,修改比较困难
应用场景:适用于需求变化不多的中小型项目,比如后台管理系统,erp,orm,oa等等
Mybatis:专注是sql本身,需要程序员自己编写sql语句,sql修改优化比较方便。Mybatis是一个不完全的orm框架,虽然自己写sql,但是也可以实现映射(输出映射,输入映射)
应用场景:
适用于需求变化较多的项目,比如:互联网项目
企业进行技术选型的原则:低成本,高回报。根据项目组的技术力量进行抉择。
4、mybatis开发dao的方法
4.1、SqlSession的使用范围
4.1.1、sqlsessionFactoryBuilder
通过sqlSessionFactoryBuilder创建会话工厂sqlSessionFactory
将sqlSessionFactoryBuilder当成一个工具类使用即可,不需要单例管理SqlSessionFactoryBuilder。
在需要创建SqlSessionFactory的时候,只需要new一次SqlSessionFactoryBuilder即可。
4.1.2、sqlSessionFactory
通过SqlSessionFactory创建SqlSession,使用单例模式管理sqlSessionFactory(工厂一旦创建,使用一个实例)
将来mybatis和spring整合后,使用单例模式管理sqlSessionFactory
4.1.3、sqlSession
sqlSession是一个面向用户(程序员)的接口
sqlSession中提供了很多操作数据库的方法:如:selectOne(返回单个对象)、selectList(返回单个或多个对象)
sqlSession是线程不安全的,在SqlSession实现类中除了有接口中的方法(操作数据库的方法)还有数据域属性
sqlSession的最佳应用场合在方法内,定义成局部变量使用
4.2原始dao开发方法(程序员需要写dao接口和实现类)
4.2.1思路
程序员需要写dao接口和dao实现类
需要向dao实现类注入SqlSessionFactory,在方法体内同归sqlSessionFactory创建SqlSession
4.2.2 dao接口
4.2.3 dao实现类
4.2.4测试代码:
4.2.5总结原始dao开发问题
1、dao接口实现类方法中存在大量的模板方法,设想能否将这些代码提取出来,大大减轻程序员的工作量
2、将statement的id硬编码了
3、调用sqlsession方法时传入的变量,由于sqlsession方法使用泛型,即变量类型传入错误,编译阶段也不报错,不利于程序员开发
4.3mapper代理方法(程序员只需要mapper接口,相当于dao接口)
4.3.1思路(mapper代理的开发规范)
程序员还需要编写mapper.xml映射文件
程序员只需要写mapper接口(相当于dao接口),需要遵循一些开发规范,Mybatis可以自动生成mapper接口实现类的代理对象
开发规范:
1、 在mapper.xml中namespace等于mapper接口地址
2、 mapper.java 接口中方法名和,mapper.xml中的statement的id一致
3、 mapper.java接口中方法输入参数和mapper.xml中parameterType一致
4、 mapper.java接口中方法返回值和mapper.xml中resultType一致
总结:
以上开发规范主要是对下边的代码进行统一生成:
User user=sqlSession.selectOne("test.findUserById", id);
sqlSession.insert("test.insertUser", user);
。。。
4.3.2mapper.java
4.3.3mapper.xml
4.3.4在配置中导入mapper.xml
4.3.5测试
4.3.6一些问题总结
1、代理对象内部调用selectOne或selectList
如果mapper方法返回单个pojo对象(非集合对象),代理对象内部通过selectOne查询数据库
如果mapper方法返回集合对象,代理对象内部通过selectList查询数据库
2、mapper方法的参数只能有一个是否影响我们系统开发?
系统框架中,dao层的代码是被业务层公用的
即使mapper接口只有一个参数,可以使用包装类型的pojo满足不同的业务方法的需求
注意:
持久层方法的参数可以为包装类型、mapper。。。,service方法中建议不要使用包装类型
5.SqlMapConfig.xml
Mybatis的全局配置文件SqlMapConfig.xml,配置内容如下:
Properties(属性)
Settings(全局配置参数)
TypeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
environment(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源)
mappers(映射器)
5.1properties属性
需求:
将数据库连接参数单独配置在db.properties中,只需要在SqlMapConfig.xml中加载db.properties的属性值。在SqlMapConfig中就不需要对数据库的连接参数硬编码
将数据库连接参数只配置在db.properties中,原因:方便对参数进行统一管理,其他xml可以引用该db.proiperties
测试代码学会一遍正常测试一遍异常测试,比较保险
注意:Mybatis将按照下面的顺序来加载属性:
在propertis元素体内定义的属性首先被读取
然后会读取properties元素中resource或url加载的属性,它会覆盖已读取的同名属性
最后读取parameterType传递的属性,它会覆盖已读取的同名属性(也就是说可能使用parameterType得到的是db.properties中的属性)
建议:
不要在properties元素体内增加任何属性值,只将属性定义在properties文件中
在properties文件中定义属性名要具有一定特殊性,比如:xxxx.xxx.xxxx
5.2 settings 全局的参数配置
Mybatis框架在运行时可以调整一些运行参数。
比如:开启二级缓存、开启延迟加载。
5.3 typeAlias(别名)
需求:在mapper.xml中定义了许多的statement,在statement中需要parameterType制定输入参数类型,resultType指定输出类型。
如果在指定类型时输入类名全路径,不方便进行开发,可以针对parameterType和resultType定义一些别名,再mapper.xml中通过别名定义,方便开发。
Mybatis默认支持别名:
针对pojo的需要我们自定义别名:
单个别名定义:
使用:
批量别名定义:
如果需要定义多个包中po类的别名,多加几个package标签即可
5.4typeHandlers(类型处理器)
Mybatis中通过typeHandlers完成jdbc类型和java类型的转换
Mybatis默认的类型处理器:
自定义类型处理器:
重写类型处理器或者创建你自己的类型处理器来处理不支持的或非标准的类型。要这样做的话,简单实现TypeHandler接口,然后映射新的类型处理器类到java类型
代码:
使用:
5.5mapper的配置(映射配置)
5.5.1加载单个mapper
Resource方式:
mapper接口加载单个配置文件:
需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在同一个目录中
5.5.2 批量加载mapper
建议使用
6、输入映射
通过parameterType指定输入参数的类型,类型可以是简单类型、hashmap,pojo对象,pojo的包装类型。
6.1简单类型:
6.2Pojo对象:
6.3传递pojo的包装对象
6.3.1需求:
完成用户信息的综合查询,需要传入查询条件(可能会包括用户信息,其他信息,比如商品的订单的)。
6.3.2定义包装类型pojo
针对前面的需求,我们建议使用自定义的包装类型的pojo
在包装类型的pojo中,将复杂的查询条件包装进去
在不修改原类的情况下,可以使用原类的扩展类,该类继承自原类
6.3.3mapper.xml
在UserMapper.xml中定义用户信息综合查询(查询条件复杂,一般是进行关联查询)
6.3.4mapper.java
6.4hashmap对象:
Mapper.xml:
Mapper.java:
测试代码:
7、输出映射
7.1resultType
使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。
如果查询出来的列名和pojo中的属性名全部不一致,没有创建pojo对象
只要查询出来的列名和pojo中的属性有一个一致,就会创建pojo对象
7.1.1输出简单类型
需求:用户信息的综合查询列表总数,通过查询总数和上边查询列表才可以实现分页
Mapper.xml:
Mapper.java:
测试代码:
小结:
查询出来的结果集只有一行且一列这个时候可以使用简单类型来进行输出映射
7.1.2输出pojo对象和pojo列表
不管是输出的是pojo单个对象还是一个pojo对象列表,在mapper.xml中returnType指定的对象类型是一样的,在mapper.java 中方法的返回值不一样
输出pojo对象,方法的返回值是pojo对象
输出pojo列表,方法的返回值是List<pojo>
生成的动态代理对象根据方法返回值选择使用selectOne或者selectList
7.1.3输出hashmap
输出pojo对象可以改用hashmap输出类型,将输出的字段名称作为map的key,value为字段值
输出pojo对象列表得到的是list<hashmap>
7.2resultMap
Mybatis中使用resultMap完成高级映射
7.2.1resultMap使用方法:
如果查询出来的列名和pojo的属性不一致,通过定义一个resultMap对列名和pojo属性名之间作一个映射关系。
定义resultMap
使用resultMap作为statement的输出映射类型
需求:将下面的sql使用resultMap完成映射
select id id_,username username_ from user where id=#{value}
mapper.xml:
Mapper.java:
测试代码:
小结:
resultType进行映射,必须列名和属性名一致才能成功。如果列名和属性名不一致则使用resultMap完成映射。
8、动态sql
8.1什么是动态sql
Mybatis核心 对SQL语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接、组装。
8.2需求
用户信息综合查询列表和用户信息查询列表总数这两个statement的定义使用动态sql
对查询条件进行判断,如果查询条件不为空,我们才进行查询条件的拼接
Mapper.xml:
测试代码:
8.3sql片段
需求:现前面动态sql中的判断条件是相同的。我们需要将前面相同的sql判断条件抽取出来,在其他地方可以直接调用。
定义sql片段:
引用sql片段:
8.3 foreach标签
向sql传递List或者数组,mybatis使用foreach解析
需求:
在用户查询列表和查询总数的statement中,增加多个id的查询。
两种解决方案:
Select * from user where id=1 or id=10 or id=16…;
Select * from user where id in (1,10,16,..);
在输入参数包装类型中添加List<Integer>属性来传入多个id
修改mapper.xml:
查询条件定义成sql片段,修改该sql片段:
Mapper.xml:
测试代码:
前面我们已经使用了if标签和where标签和foreach标签。
Choose(when,otherwise)
和jstl中的c:choose一样使用:
Where,trim和set
Where:
特点:连接查询条件,相当于一个“where”字符串,自带空格,会自动去掉开头的“AND”和“OR”
Trim:如果where无法满足你的需求,你可以自定义使用trim得到效果
Prefix:相当于什么字符串
PrefixOverrides:忽略第一个什么字符串
Set:更新语句中使用,会自动前置set关键字,也会消除任意无关的逗号