day62_mybatis_springMVC_spring整合

来源:互联网 发布:湖北旅游 知乎 编辑:程序博客网 时间:2024/06/18 16:20

Mybatis第二天

课程安排:

以订单商品案例学习mybatis的关联查询:学习订单商品数据模型(数据表、表之间关系)(掌握)使用mybatis实现:一对一一对多多对多使用resultType和resultMap实现。resultType(掌握)resultMap(了解)mybatis延迟加载(了解)mybatis缓存:一级缓存(了解)二级缓存(掌握性能优化方法)Mybatis和spring整合:(重点)    Mybatis+spring+springmvc整合Mybatis逆向工程:(掌握,企业实际开发中使用较多)由数据表生成mapper.xml、mapper.java、po类工作流案例系统:企业采购系统架构:Mybatis+spring+springmvc系统部署

1 复习

1.1Mybatis是什么?

是apache的开源项目,是一个持久层的框架,对jdbc进行封装,是一个不完全ORM框架。需要程序员手动编写sql,自动去完成向sql中映射输入参数,sql查询结果映射成java对象。

Mybatis应用场合:对需求变更大的项目,关系数据模型不固定,比如互联网项目,建议使用mybatis,灵活去编写sql语句,对sql语句进行修改、优化方便。

1.2 Mybatis开发过程

1、配置SqlMapConfig.xml(全局配置文件,名称不固定)2、配置XXXMapper.xml映射文件3、根据配置创建SqlSessionFactory SqlSessionFactory在实际使用时,建议使用单例模式4、根据SqlSessionFactory创建SqlsessionSqlsession是一个面向用户的接口,是线程不安全的,最佳应用场合是方法体内SqlSession提供操作数据库的常用方法,内部使用Exceutor(基本执行器、缓存执行器)底层封装类操作数据库。5、通过Sqlsession操作数据库对于插入、删除、更新进行事务提交SqlSesssion使用完毕进行关闭。

1.3 动态Sql

#{}或${}:#{}是占位符。(建议使用#{})${}是拼接sql符号。

If判断:根据条件进行sql 拼接。
Sql片段:将公用的sql(查询条件、表的查询列)抽取出来组成 一个sql片段,在其它的mapper.xml中就可以引用了(如果跨namespace,引用时:namespace.sql片段的id)

1.4 resultType和resultMap区别

resultType:指定sql查询结果集中单条记录所映射的java对象,要求sql查询的列名和java对象(pojo)的属性名必须一致方可映射成功。
resultMap:如果 sql查询的列名和java对象(pojo)的属性名不一致,定义一个resultMap将sql查询的列名和java对象(pojo)的属性名作一个对应关系,最终将sql查询结果映射到java对象中。

2 订单商品数据模型

环境准备:
订单商品数据模型包括的数据库表:
这里写图片描述

在mysql数据库执行sql_table.sql。
这里写图片描述

需求:用户购买(一次可以购买多个)商品,需要创建订单(可以创建多个),一个订单中包括了(购买的商品、购买数量、购买价格)

上边表之间的关系:
1、搞清楚数据库级别表之间的关系(外键关系)
2、搞清楚业务关系(根据具体业务需求分析)

这里写图片描述

注意:在分析表之间的业务关系时一定要在某个业务意义基础上来分析。

3 订单商品一对一查询

3.1 需求

查询所有订单信息,关联查询订单所属用户信息。

3.2 方法1 使用resultType

3.2.1Sql语句:
主查询表:根据需求条件显示主体信息,不能因为和关联表关联导致主体信息无法显示。
订单信息表orders
关联查询表(用户表:user):显示关联信息,使用内链接。
使用内链接还是外链接:
内链接:如果主查询表和关联查询表存在外键关系就可以使用内链接。
外链接:主查询表中和关联表没有外键关系,查询的主表信息一部分在关联查询表中,此时要用外链接。

SELECT   orders.*,  user.username,  user.addressFROM  orders,  USER WHERE orders.user_id = user.id

根据表结构创建po类:
这里写图片描述

3.2.2maper.xml:

定义statement时,resultType指定pojo包括上边sql查询的所有字段(订单信息、用户信息),需要自定义一个pojo继承原始的po类,自定义的pojo中包括订单信息、用户信息。

开发经验:自定义的pojo建议继承sql查询列较多的po类。
这里写图片描述

这里写图片描述

3.2.3Mapper.java
这里写图片描述

3.3 方法2 使用resultMap

3.3.1实现目标
通过订单查询用户,一个订单只能关联查询出一个用户,在订单的po类中创建一个user属性(记录用户信息),让resultMap将sql查询结果集中用户信息映射到订单po类的user属性中。

3.3.2在Orders.java中添加User属性
这里写图片描述

3.3.3Mapper.xml

定义resultMap:
这里写图片描述

这里写图片描述

3.3.4Mapper.java
这里写图片描述

3.4 resultType和resultMap对比

resultType:实现查询时,需要自定义pojo,pojo的属性名和sql查询列名一致。企业开发中resultType简单方便建议使用。

resultMap:可以将sql查询结果信息中部分属性映射到一个pojo中。需要程序员进行映射配置,比较麻烦。
针对一对一查询建议使用resultType。
如果一对一查询要使用mybatis提供的延迟加载 功能,必须使用resultMap。

4 订单商品一对多查询

4.1 需求

查询所有订单信息及订单下的订单明细信息

4.2 Sql语句

主查询表:订单信息

关联查询表:订单明细信息,使用内链接

SELECT   orders.*,  user.username,  user.address,  orderdetail.id orderdetail_id,  orderdetail.item_id,  orderdetail.item_num,  orderdetail.item_priceFROM  orders,  USER,  orderdetailWHERE orders.user_id = user.id AND orders.id = orderdetail.orders_id

4.3 使用resultMap将订单明细信息映射到Orders.java的属性中

在Orders.java创建订单明细属性(是一个集合对象,因为一个订单对应多个明细)。
这里写图片描述
目标:将订单及订单明细映射到orders类中,将明细信息(多个)映射到List orderdetails。

4.4 Mapper.xml

定义resultmap:
这里写图片描述

这里写图片描述

4.5 Mapper.java

这里写图片描述

4.6 小结

使用resultType是无法将查询结果映射到一个list集合对象中,只能使用resultMap将查询结果映射到list集合对象中。

5 订单商品多对多查询

5.1 需求

查询所有订单信息及订单明细的商品信息

5.2 Sql语句

主查询表:订单表
关联查询表:用户表、订单明细表、商品表

SELECT   orders.*,  user.username,  user.address,  orderdetail.id orderdetail_id,  orderdetail.item_id,  orderdetail.item_num,  orderdetail.item_price ,  items.item_detail,  items.item_name,  items.item_price item_price_priceFROM  orders,  USER,  orderdetail,  items WHERE orders.user_id = user.id   AND orders.id = orderdetail.orders_id   AND orderdetail.item_id = items.id

5.3 使用resultMap将订单明细及商品信息映射

因为商品信息和订单明细有外键关联,在订单明细po类添加商品信息属性:
这里写图片描述

目标:resultMap将订单明细映射到orders.java中的List orderdetails,将商品信息映射到Orderdetail.java中商品属性中(Items items)。

5.4 Mapper.xml

定义resultMap:
目标:resultMap将订单明细映射到orders.java中的List orderdetails,将商品信息映射到Orderdetail.java中商品属性中(Items items)。
这里写图片描述

这里写图片描述

5.5 Mapper.java

这里写图片描述

5.6 小结

使用resultType是无法将查询结果映射到一个list集合对象中,只能使用resultMap将查询结果映射到list集合对象中。

6 延迟加载

延迟加载意义:在需求允许的情况下,先查询单表,当需要关联其它表查询时,进行延迟加载,去关联查询,达到目标:不需要关联信息时不查询,需要时再查询。好处:提高数据库的性能。

6.1 需求

查询订单信息,关联查询用户信息。
延迟加载需求:首次只查询订单信息,当需要关联查询用户信息时,再查询用户信息。

6.2 方法1不使用mybatis提供延迟加载特性

定义两个mapper接口。
1、查询订单信息列表
2、根据用户id查询用户信息

查询过程:
首次查询只调用第一个mapper接口(查询订单信息列表)
当需要查询某个订单的用户信息时,从订单信息中获取用户id,调用第二个mapper(根据用户id查询用户信息)。

6.3 使用mybatis提供延迟加载 特性

6.3.1打开延迟加载开关

在SqlMapConfig.xml中配置setting全局参数:

lazyLoadingEnabled:延迟加载的总开关,设置为true
aggressiveLazyLoading:设置为false,实现按需加载(将积极变为消极)
这里写图片描述

6.3.2定义mapper.xml

定义statement,只查询订单。
在OrdersMapperCustom.xml定义:
这里写图片描述

还需要定义一个根据用户id查询用户信息的statement。
在UserMapper.xml定义:
这里写图片描述

配置延迟加载 :

要根据订单信息中的用户id(外键)查询用户信息,修改上边订单信息查询的statement。
将resultType改为resultMap,
定义resultMap,配置延迟加载:
这里写图片描述

6.3.3Mapper.java
这里写图片描述

6.3.4测试

调用上边的mapper接口,查询到仅仅是订单信息。

遍历订单信息,如果要获取用户信息(调用getUser()方法),进行延迟加载,调用查询用户信息的sql。

测试跟踪:
查询订单信息,日志发现只能有一条sql(查询订单信息)
这里写图片描述
当调用getUser()方法,日志中打出查询用户信息的sql
这里写图片描述

6.4 小结

使用association关联查询单个对象和使用collection关联查询集合对象都支持延迟加载。

7 缓存

7.1 为什么使用缓存

将从数据库中查询出来的数据缓存起来,缓存介质:内存、磁盘,从缓存中取数据,而不从数据库查询,减少了数据库的操作,提高了数据处理性能。

7.2 一级缓存

Mybatis默认提供一级缓存,缓存范围是一个sqlSession。

在同一个SqlSession中,两次执行相同的sql查询,第二次不再从数据库查询。

测试:
这里写图片描述

这里写图片描述

执行提交清除缓存测试:
如果第一次查询后,执行commit提交,mybatis会清除缓存,第二次查询从数据库查询。
这里写图片描述

这里写图片描述

7.2.1一级缓存原理:

一级缓存采用Hashmap存储,mybatis执行查询时,从缓存中查询,如果缓存中没有从数据库查询。
如果该SqlSession执行commit()提交,清除缓存。

Map的key:(code+。。statement的id+sql+输入参。。)
这里写图片描述

7.3二级缓存
缓存范围是跨SqlSession的,范围是mapper的namespace,相同的namespace使用一个二级缓存结构。

需要进行参数配置让mybatis支持二级缓存。

7.3.1二级缓存配置
3、在核心配置文件SqlMapConfig.xml中加入,表示打开二级缓存开关

4、还需要在mapper.xml中配置是否打开该mapper的二级缓存。
这里写图片描述

7.3.2二级缓存注意事项

实现序列化:
注意:将查询结果的pojo对象进行序列化实现 java.io.Serializable接口
这里写图片描述

如何清除缓存:
执行相同的statement,如果执行提交操作需要清除二级缓存。

如果想让statement执行后刷新缓存(清除缓存),在statement中设置flushCache=”true” (默认值 是true)

设置statement是否开启二级缓存
如果让某个statement启用二级缓存,设置useCache=true(默认值为true)

7.3.3测试

在测试方法,创建多个Sqlsession。
这里写图片描述

这里写图片描述

提交事务后,清除二级测试:
再创建一个SqlSession,执行用户更新,清除二级缓存。
这里写图片描述

这里写图片描述

测试 useCache=”false”:

修改statement的useCache为false,表示该statement不再进行二级缓存
这里写图片描述

测试 flushCache=”false”
修改更新用户的statement,
这里写图片描述

执行更新操作后,不刷新二级缓存。

7.3.4二级缓存原理

如果二缓存开启,首先从二级缓存查询数据,如果二级缓存有则从二级缓存中获取数据,如果二级缓存没有,从一级缓存找是否有缓存数据,如果一级缓存没有,查询数据库。

7.3.5二级缓存应用场景(重点)

1、针对复杂的查询或统计的功能,用户不要求每次都查询到最新信息,使用二级缓存,通过刷新间隔flushInterval设置刷新间隔时间,由mybatis自动刷新。
比如:实现用户分类统计sql,该查询非常耗费时间。
将用户分类统计sql查询结果使用二级缓存,同时设置刷新间隔时间:flushInterval(一般设置时间较长,比如30分钟,60分钟,24小时,根据需求而定)

2、针对信息变化频率高,需要显示最新的信息,使用二级缓存。
将信息查询的statement与信息的增、删、改定义在一个mapper.xml中,此mapper实现二级缓存,当执行增、删、修改时,由mybatis及时刷新缓存,满足用户从缓存查询到最新的数据。
比如:新闻列表显示前10条,该查询非常快,但并发大对数据也有压力。
将新闻列表查询前10条的sql进行二级缓存,这里不用刷新间隔时间,当执行新闻添加、

最佳的方案使用页面缓存。

7.3.6二级缓存使用Ehcache

Mybatis控制二级缓存策略,二级缓存缓存介质使用Ehcache。
让Ehcache和mybatis进行整合。

配置过程参考笔记。

8 Mybatis和spring整合

8.1 搭建环境

8.1.1Jar包

Mybatis3.2.3+spring3.1.4+springmvc3.1.4

Mybatis和spring整合:
从mybatis官方下载Mybatis和spring整合包:mybatis-spring-1.2.2.jar
这里写图片描述

Mybatis3.2.3+spring3.1.4+springmvc3.1.4的jar包括:

Mybatis核心和Mybatis依赖包
Mybatis和spring整合包
Spring的jar(包括springmvc的jar包)
数据库驱动包
第三方数据库连接池
这里写图片描述

8.1.2配置文件
这里写图片描述

db.properties—数据库连接参数

log4j.properties—日志 配置文件
mybatis/SqlMapConfig.xml—mybatis全局配置文件
spring/springmvc.xml———-springmvc的全局配置文件
spring/applicationContext.xml—spring配置文件(配置公用内容:数据源、事务)
spring/ applicationContext- dao.xml—spring和mybatis整合的配置(SqlSessionFactory、mapper配置)
spring/ applicationContext-service.xml—配置业务接口

8.1.3工程结构
这里写图片描述

8.2 整合思路

这里写图片描述

整合步骤:
1、整合持久层
Mybatis和spring整合
整合目标:mapper创建由spring来管理
SqlSessionFactory由spring管理(设置单例 )

2、整合业务层
Spring管理service
整合目标:Service通过spring调用mapper

3、整合控制层
因为springmvc是spring一个模块,只要加入jar包,配置springmvc.xml和web.xml即可。
整合目标:action中通过spring调用service

8.3 整合持久层

目标:mapper创建由spring来管理

8.3.1方法1通过spring开发原始dao

8.3.1.1准备环境:
applicationContext.xml
配置数据源:

开发阶段数据库最大连接数建议设置小一点够用即可。
这里写图片描述

SqlMapConfig.xml
这里写图片描述

8.3.1.2让spring管理SqlSessionFactory
在applicationContext-dao.xml配置SqlSessionFactory
从mybatis和spring的整合包找SqlSessionFactory:
这里写图片描述

这里写图片描述

8.3.1.3开发dao
程序员需要写dao接口和dao实现类。

编写dao的实现类,继承SqlSessionDaoSupport
这里写图片描述

定义User.xml,且在SqlMapConfig.xml中配置。
这里写图片描述

这里写图片描述

在applicationContext-dao.xml配置dao:
这里写图片描述

8.3.1.4测试
加载spring容器,从容器中取出UserDao的bean。
这里写图片描述

8.3.1.5小结

由于企业中原来使用的是ibatis,很多使用原始dao开发方法。

8.3.2方法2通过spring生成mapper动态代理

Mybatis和spring整合使用mapper动态代理的开发方法

8.3.2.1开发mapper接口。
这里写图片描述

8.3.2.2在applicationContext-dao.xml配置mapper(让spring生成动态代理)
这里写图片描述

8.3.2.3问题

需要在spring容器中配置每个mapper接口,比较麻烦。
使用下边讲的扫描器来解决。

8.3.2.4使用mapper批量扫描器自动创建代理对象

从mybatis和spring整合包找扫描器。
这里写图片描述

在applicationContext-dao.xml中配置扫描器:
这里写图片描述

由于使用spring和mybatis整合的mapper扫描器,原来在SqlMapConifg.xml配置mapper项就可以省略了。

使用扫描器简单方便,最终使用mapper扫描器方式。

8.4 整合业务层

Spring管理service
整合目标:
Service通过spring调用mapper
由spring进行事务控制

8.4.1开发service接口
这里写图片描述

8.4.2Service接口交给spring管理
为了方便系统维护企业开发中建议使用配置方式,在applicationContext-service.xml配置service。
这里写图片描述

8.4.3测试 service
加载spring容器,加载配置文件包括:
这里写图片描述

这里写图片描述

8.4.4事务控制

为了规范程序员编码,采用声明式事务配置方式。

在applicationContext.xml配置事务管理:

<!-- 事务管理器    mybatis使用jdbc事务管理     -->    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">        <!-- 数据源 -->        <property name="dataSource" ref="dataSource"/>    </bean>    <!-- 通知 -->    <tx:advice id="txAdvice" transaction-manager="transactionManager">        <!-- 配置传播行为 -->        <tx:attributes>            <tx:method name="save*" propagation="REQUIRED"/>            <tx:method name="insert*" propagation="REQUIRED"/>            <tx:method name="update*" propagation="REQUIRED"/>            <tx:method name="delete*" propagation="REQUIRED"/>            <tx:method name="find*" propagation="SUPPORTS" read-only="true"/>            <tx:method name="get*" propagation="SUPPORTS" read-only="true"/>            <tx:method name="select*" propagation="SUPPORTS" read-only="true"/>        </tx:attributes>    </tx:advice>    <!-- aop配置 -->    <aop:config>        <aop:advisor advice-ref="txAdvice"         pointcut="execution(* cn.itcast.ssm.service.impl.*.*(..))"/>    </aop:config>

8.4.5测试事务

一个service方法是一个事务单元 。

创建一个service方法,方法中发起多次数据库操作,只要有一个次操作失败(抛出runtime异常)事务回滚,该方法中其它成功操作自动回滚。

Service方法:
这里写图片描述

8.5 整合控制层

整合目标:action中通过spring调用service

8.5.1准备环境

8.5.1.1配置Springmvc.xml:
Springmvc.xml,处理器映射器、处理器适配器(可以mvc注解驱动规则这两个处理器映射器、处理器适配器),视图解析器。

配置action的组件扫描。
这里写图片描述

8.5.1.2配置前端控制器

在web.xml配置:
这里写图片描述

8.5.1.3在web.xml加载spring容器

通过统配符加载spring配置文件:
这里写图片描述

配置文件包括:
这里写图片描述

8.5.1.4编写action
需求:通过调用userService取出用户信息,在页面显示。
这里写图片描述

8.5.1.5编写页面
这里写图片描述

8.5.1.6Tomcat部署测试

访问路径 :http://localhost:8080/mybatis1218_ssm/user/queryUser.action?id=10

9 Mybatis逆向工程

Mybatis官方提供逆向工程,实现由数据库表生成mapper.xml、mapper.java、po类 及相关类。

9.1 下载逆向工程

这里写图片描述

使用方式:
这里写图片描述

使用java程序方式执行逆向工程。

9.2 创建逆向工程

单独 创建java工程:generatorSqlmapCustom
这里写图片描述

9.3 逆向工程配置文件

添加配置文件,在配置文件逆向工程配置信息,根据配置信息生成表相关的mapper文件。
这里写图片描述

注意需要配置:
数据库连接参数
Po类存放位置
Mapper映射文件和mapper接口的存放位置
配置表名

9.4 写java执行逆向工程

这里写图片描述

9.5 拷贝 逆向工程中生成的代码拷贝到正式工程

这里写图片描述

注意:尽量不要修改自动生成的类。

9.6 学习生成mapper接口使用方法

//根据主键删除    @Test    public void testDeleteByPrimaryKey() {        studentMapper.deleteByPrimaryKey(4);        //自定义条件删除,符合条件的全部删除        //studentMapper.deleteByExample(example)    }    //添加信息    @Test    public void testInsert() {        //插入对象        Student student = new Student();        student.setName("赵六");        studentMapper.insert(student);    }    //根据查询条件查询信息    @Test    public void testSelectByExample() {        //自定义条件        StudentExample studentExample = new StudentExample();        StudentExample.Criteria criteria = studentExample.createCriteria();        //拼接查询条件        criteria.andSexEqualTo("2");//sex等于2        criteria.andNameEqualTo("王五");//姓名 等于王五        //根据查询条件查询返回集合对象        List<Student> list = studentMapper.selectByExample(studentExample);        System.out.println(list.size());    }    //根据主键查询信息    @Test    public void testSelectByPrimaryKey() {        Student student = studentMapper.selectByPrimaryKey(1);        System.out.println(student);    }    @Test    public void testUpdateByPrimaryKeySelective() {        //传入更新对象,必须要id,对象中不空的属性才更新        Student student = new Student();        student.setId(3);        student.setName("王五");        studentMapper.updateByPrimaryKeySelective(student);    }    //根据主键更新信息    @Test    public void testUpdateByPrimaryKey() {        //传入更新对象,必须要id,不管对象中属性是否为空全部更新        //必须先从数据库查询出原始记录        Student student = studentMapper.selectByPrimaryKey(3);        //设置更新内容        student.setName("王小五");        studentMapper.updateByPrimaryKey(student);    }

10 采购系统

需求:员工创建采购单、经理审核采购单。
员工和经理信息在pur_sys_user表中。
密码:全部111111。

导入mysql数据库:
这里写图片描述

在eclipse中导入 工程:
这里写图片描述

0 0
原创粉丝点击