车主之友微信订阅号去水印?去哪个微信订阅号去水印好?

本帖子已过去太久远了,不再提供回复功能。4104人阅读
mybatis(1)
在实际开发中,经常会遇到一个方法里需要更新多张表的情况,在使用spring+mybatis的时候,我们一般写多个dao方法分别与mapper中&update&或&insert&标签对应,然后在service中调用这么多个dao方法,这样不仅浪费人力物力,代码也不好看,全是updateXx1/updateXx2/insertXx3/insertXx4等。
笔者经过查看mybatis的源码,发现mybatis确实不支持一个&update&中写多条语句,这是因为mybatis底层其实是使用PreparedStatement实现的,这个东西在初始化的时候就得传一个sql语句进去,然后对于?参数再使用setXxx()填充进去,mybatis为了偷懒就没有实现多条语句的操作。
笔者经过慎重思考及实验,得出以下三种实现方法:
1. 使用Statement,把sql语句写在代码里,通过其addBatch(sql)方法(此方法无法在PreparedStatement中使用)把sql语句加进去,然后批量执行,但是这种方法有个问题,你得先把参数写死在sql中,这当然是不建议的啦,sql注入,你懂的~~
2. 使用存储过程,这当然是最简单的方法啦,但是,你得先能干得过DBA,再说了,你不能每次两次以上的更新都去麻烦DBA,不是么~~
3. 自己通过mybatis的API改造出来一个可以多次更新的方法,以下介绍的方法就使用这种方法^_^
笔者把mybatis的API翻了个底朝天,终于写出了以下方法,直接上代码:
(以下代码,为节约空间,把package和import都干掉了)
* VO 公共数据库操作dao
public class BaseSqlDaoImpl&T& implements BaseSqlDao&T& {
private static Logger logger = LoggerFactory.getLogger(BaseSqlDaoImpl.class);
* Mapper包路径
private String baseMapperP
public String getBaseMapperPackage() {
return baseMapperP
public void setBaseMapperPackage( String baseMapperPackage ) {
this.baseMapperPackage = baseMapperP
private SqlSessionFactory sqlSessionF
* Alan添加,用于一个mapper更新多个表
* (1)Connection不用close,mybatis自己会回收;
* (2)使用此方法可以使用spring的事务管理
* DaoException
public void updateMultiTables( Map&String, Object& params ) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
PreparedStatement ps = null;
String selectVoName =
params.get("selectVoName") == null ? "baseSelectListByVo" : params.get("selectVoName").toString();
String mapperName = getBaseMapperPackage() + "." + params.get("mapperClassType");
Connection connection = sqlSession.getConnection();
BoundSql boundSql =
sqlSession.getConfiguration().getMappedStatement(mapperName + "." + selectVoName).getBoundSql(params);
String[] sqls = boundSql.getSql().split(";");
List&ParameterMapping& list = boundSql.getParameterMappings();
int i = 0;
int j = 0;
for( ; i & sqls. i++ ) {
String sql = sqls[i].trim();
if(logger.isDebugEnabled()) {
logger.debug("Alan print log for you -===& Preparing: " + sql);
ps = connection.prepareStatement(sql);
int questionMarkCount = ps.getParameterMetaData().getParameterCount();
StringBuilder sb = null;
if(logger.isDebugEnabled()) {
sb = new StringBuilder();
for( int k = 1, length = j + questionMarkC j & j++, k++ ) {
Object param = null;
String propertyName = list.get(j).getProperty();
if(boundSql.hasAdditionalParameter(propertyName)) {
param = boundSql.getAdditionalParameter(propertyName);
MetaObject metaObject = sqlSession.getConfiguration().newMetaObject(params);
param = metaObject.getValue(propertyName);
ps.setObject(k, param);
if(logger.isDebugEnabled()) {
sb.append(param==null?"null":param.toString()).append("(").append(param==null?list.get(j).getJavaType().getSimpleName():param.getClass().getSimpleName()).append("),");
if(logger.isDebugEnabled() && sb.length() & 0) {
logger.debug("Alan print log for you -==& Parameters: " + sb.toString().substring(0, sb.length() - 1));
int total = ps.executeUpdate();
if(logger.isDebugEnabled()) {
logger.debug("Alan print log for you -&== Total: " + total);
ps.close();
catch(Exception e) {
logger.error("", e);
if(ps != null) ps.close();
sqlSession.close();
简单分析:把&update&中的多个语句取出来用分号”; “分割,每一条语句装入到PreparedStatement中,再把params中的参数set到对应占位符 ? 上。
在service的基类中添加以下方法:
public abstract class BaseCrudServiceImpl implements BaseCrudService {
* 更新多张表
@SuppressWarnings( "unchecked" )
public void updateMultiTables( Map&String, Object& params ) throws ServiceException {
BaseSqlDao&Object& baseSqlDao = (BaseSqlDao&Object&) SpringComponent.getBean("baseSqlDao");
baseSqlDao.updateMultiTables(params);
catch(Exception e) {
logger.error("update multi-tables error");
throw new ServiceException("", e);
这样,只要继承了BaseCrudServiceImpl 类的service中直接调用即可。
在service中调用代码如下:
@Service( "testService" )
public class TestServiceImpl extends BaseCrudServiceImpl implements TestService {
@Transactional( propagation = Propagation.REQUIRED, rollbackFor = Exception.class )
public void testUpdateMultiTables( Map&String, Object& params ) {
updateMultiTables(params);
public BaseCrudDao init() {
return null;
单元测试类如下:
@RunWith( SpringJUnit4ClassRunner.class )
@ContextConfiguration( locations = "classpath*:META-INF/applicationContext.xml" )
public class BaseTest0 extends AbstractJUnit4SpringContextTests {
TestService testS
public void test() {
Map&String, Object& params = new HashMap&String, Object&();
BasicUserInfo userInfo = new BasicUserInfo();
userInfo.setCityId(440300);
userInfo.setCityName("深圳市2");
userInfo.setMobile("");
userInfo.setNickName("唐彤");
userInfo.setUserId(7771904L);
params.put("selectVoName", "testMultiTables");
params.put("mapperClassType", "TestMapper");
params.put("param1", 1);
params.put("param2", 2);
params.put("param3", "10.1.20.75");
params.put("param4", "ttxx");
params.put("user", userInfo);
List&Integer& list = new ArrayList&Integer&();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
params.put("list", list);
testService.testUpdateMultiTables(params);
catch(Exception e) {
logger.error("update multi-tables error");
throw new ServiceException("", e);
xml中配置如下:
id="testMultiTables"&
update basic_bank_info set name = #{param4} where id = #{param2};
delete from basic_user_gift_package_mapping where user_id = #{user.userId};
insert into basic_like_log values(#{user.userId},#{user.userId},#{param1},now(),#{user.nickName},#{param3});
update basic_area set name = #{user.cityName} where area_id = #{user.cityId};
update basic_bank_info set name = #{param3} where id in
collection="list" item="id" index="index" open="(" close=")" separator=","&
可见上述一共有五条sql语句,其中参数包括基本类型、对象类型和list类型,执行单元测试,打印日志如下:
可以看见五条sql语句都正确执行了,事务提交之后,connection自动释放(Release)。
以上即为笔者拙见,有不得当的地方欢迎提出来,大家如果有好的方法也欢迎推荐,谢谢~~
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:42430次
排名:千里之外
原创:28篇
评论:20条
(2)(3)(2)(2)(2)(2)(3)(1)(3)(5)(5)mybatis实现简单的增删查改
时间: 09:14:50
&&&& 阅读:99
&&&& 评论:
&&&& 收藏:0
标签:接触一个新技术,首先去了解它的一些基本概念,这项技术用在什么方面的。这样学习起来,方向性也会更强一些。我对于mybatis的理解是,它是一个封装了JDBC的java框架。所能实现的功能是对数据库进行增删查改的功能。
首先,需要搭建一个demo,用于学习这个框架的使用方式。(1)在IDE上建立自己的工程目录,一个普通的java工程项目就好,我电脑本地的IDE是Myeclipse。(2)引入搭建框架需要的jar包,这个直接去网上搜索就好。(3)框架的核心实现都是基于配置的,引入jar包后,先配置mybatis的核心xml文件,我自己命名为mybatis.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&
&environments default="development"&
&environment id="development"&
&transactionManager type="JDBC" /&
&!-- 配置数据库连接信息 --&
&dataSource type="POOLED"&
&property name="driver" value="${driver}" /&
&property name="url" value="${url}" /&
&property name="username" value="${username}" /&
&property name="password" value="${password}" /&
&/dataSource&
&/environment&
&/environments&
&/configuration&
environments 和 environment这两个标签,里面的属性值,我直接按照官方提供的API定义,重点是dataSource标签下面的子标签,四个property分别用于指定数据库连接驱动,数据库连接地址,用户名、密码。这些信息统一使用properties文件配置。properties文件的信息如下
  driver = com.mysql.jdbc.Driver  url = jdbc:mysql://localhost:3306/crm  username = root  password =root
(4)上面的配置是一些全局配置,下一步需要建立一个实体,映射mysql数据库中的某张表,我这里的表名叫A。建立的实体类叫User
public class User {
public Integer getId() {
public void setId(Integer id) {
public String getName() {
public void setName(String name) {
this.name =
public String getAge() {
public void setAge(String age) {
this.age =
public String getScore() {
public void setScore(String score) {
this.score =
public String toString(){
return "id = " + id + " "
+"name = " + name + " "
+"age = " + age + " "
+"score = " + score + " ";
建立好实体类后,再去配置实体类对应的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.test.IUserOperation"&
&select id="getSingle" parameterType="int" resultType="com.domain.User"&
select * from A where id = #{id}
&select id="ALL" parameterType="int" resultType="com.domain.User"&
select * from A
&delete id="deleteOne" parameterType="com.domain.User"&
delete from A where id = #{id}
&select id="findByUserId" parameterType="int" resultType="com.domain.User"&
select * from A where id = #{id}
&insert id="addUser" parameterType="com.domain.User" useGeneratedKeys="false" keyProperty="id"&
insert into A values (#{id},#{name},#{age},#{score})
&update id="updateUser" parameterType="com.domain.User" &
update A set name = #{name},age = #{age},score = #{score} where id = #{id}
&delete id="deleteUser" parameterType="int"&
delete from A where id = #{id}
这个配置里的namespace必须是唯一的,而且是你需要映射的实体类的绝对路径,我这边设计为基础接口的开发方式,所以映射到的是我的接口。接口里定义了相关的增添查改的方法,配置如下
interface IUserOperation{
User findByUserId(Integer id);
void addUser(User u );
void updateUser(User u);
void deleteUser(Integer id);
接口中的方法名,对应xml文件里的select、update、insert、delete标签下的id名字,必须完全相同,否则会报错。在对应的标签下,编写你想要实现的sql语句。其中的#{id}、#{name}这些是用于接收参数的。编写完后,就可以写测试类去测试啦。
public class MyBatisTest {
private static final String confPath = "mybatis.xml";
private static final String propertiesPath = "message.properties";
private static SqlSessionFactory ssf = null;
private static SqlSession session = null;
InputStream in
= MyBatisTest.class.getClassLoader().getResourceAsStream(confPath);
Properties pro = new Properties();
pro.load(MyBatisTest.class.getClassLoader().getResourceAsStream(propertiesPath));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
ssf = new SqlSessionFactoryBuilder().build(in,pro);
ssf.openSession();
* 查询测试
public static void testSelect(){
IUserOperation iUser = session.getMapper(IUserOperation.class);
User u = iUser.findByUserId(5);
System.out.println(u.toString());
session.close();
* 删除测试
public static void testDelete(){
IUserOperation iUser = session.getMapper(IUserOperation.class);
iUser.deleteUser(14);
session.close();
* 修改数据
public static void testUpdate(){
IUserOperation iUser = session.getMapper(IUserOperation.class);
User u = new User();
u.setId(3);
u.setName("TEST_COME");
u.setAge("87");
u.setScore("100");
iUser.updateUser(u);
session.close();
* 数据添加
public static void testAdd(){
IUserOperation iUser = session.getMapper(IUserOperation.class);
User u = new User();
u.setId(14);
u.setAge("33");
u.setName("liberation");
u.setScore("**");
iUser.addUser(u);
session.close();
public static void main(String[] args) {
//testAdd();
//testUpdate();
//testDelete();
testSelect();
官方API上建议,把session设置为局部变量,我这里偷懒,设为全局变量。标签:
&&国之画&&&& &&
版权所有 京ICP备号-2
迷上了代码!mybatis第二天& 高级映射 查询缓存 和spring整合
&课程复习:
mybatis是什么?
mybatis是一人持久层框架,mybatis是一个不完全的ORM框架。sql语句需要程序员自己去编写,但是mybatis也有映射(输入参数映射、输出结果映射)。
mybatis入门门槛不高,学习成本低,让程序员把精力放在sql语句上,对sql语句优化非常方便,适用与需求变化较多项目,比如互联网项目。
mybatis框架执行过程:
1、配置mybatis的配置文件,SqlMapConfig.xml(名称不固定)
2、通过配置文件,加载mybatis运行环境,创建SqlSessionFactory会话工厂
&&&&&&&& SqlSessionFactory在实际使用时按单例方式。
3、通过SqlSessionFactory创建SqlSession
&&&&&&&& SqlSession是一个面向用户接口(提供操作数据库方法),实现对象是线程不安全的,建议sqlSession应用场合在方法体内。
4、调用sqlSession的方法去操作数据。
&&&&&&&& 如果需要提交事务,需要执行SqlSession的commit()方法。
5、释放资源,关闭SqlSession
mybatis开发dao的方法:
1、原始dao 的方法
&&&&&&&& 需要程序员编写dao接口和实现类
&&&&&&&& 需要在dao实现类中注入一个SqlSessionFactory工厂。
2、mapper代理开发方法(建议使用)
&&&&&&&& 只需要程序员编写mapper接口(就是dao接口)
&&&&&&&& 程序员在编写mapper.xml(映射文件)和mapper.java需要遵循一个开发规范:
&&&&&&&& 1、mapper.xml中namespace就是mapper.java的类全路径。
&&&&&&&& 2、mapper.xml中statement的id和mapper.java中方法名一致。
&&&&&&&& 3、mapper.xml中statement的parameterType指定输入参数的类型和mapper.java的方法输入 参数类型一致。
&&&&&&&& 4、mapper.xml中statement的resultType指定输出结果的类型和mapper.java的方法返回值类型一致。
SqlMapConfig.xml配置文件:可以配置properties属性、别名、mapper加载。。。
输入映射:
&&&&&&&& parameterType:指定输入参数类型可以简单类型、pojo、hashmap。。
&&&&&&&& 对于综合查询,建议parameterType使用包装的pojo,(将各种pojo包装在一个单独的类)有利于系统 扩展。
输出映射:
&&&&&&&& resultType:
&&&&&&&& &&&&&&&& 查询到的列名和resultType指定的pojo的属性名一致,才能映射成功。
&&&&&&&& reusltMap:
&&&&&&&& &&&&&&&& 可以通过resultMap 完成一些高级映射。
&&&&&&&& &&&&&&&& 如果查询到的列名和映射的pojo的属性名不一致时,通过resultMap设置列名和属性名之间的对应关系(映射关系)。可以完成映射。
&&&&&&&& &&&&&&&& 高级映射:
&&&&&&&& &&&&&&&& &&&&&&&& 将关联查询的列映射到一个pojo属性中。(一对一)
&&&&&&&& &&&&&&&& &&&&&&&& 将关联查询的列映射到一个List&pojo&中。(一对多)
动态sql:(重点)
&&&&&&&& if判断(掌握)
&&&&&&&& where
&&&&&&&& foreach
&&&&&&&& sql片段(掌握)
课程安排:
对订单商品数据模型进行分析。
高级映射:(了解)
&&&&&&&& 实现一对一查询、一对多、多对多查询。
&&&&&&&& 延迟加载
&&&&&&&& 一级缓存
&&&&&&&& 二级缓存(了解mybatis二级缓存使用场景)
mybatis和spirng整合(掌握)
逆向工程(会用)
1&&&&&& 订单商品数据模型
1.1&&&& 数据模型分析思路
1、每张表记录的数据内容
&&&&&&&& 分模块对每张表记录的内容进行熟悉,相当 于你学习系统 需求(功能)的过程。
2、每张表重要的字段设置
&&&&&&&& 非空字段、外键字段
3、数据库级别表与表之间的关系
&&&&&&&& 外键关系
4、表与表之间的业务关系
&&&&&&&& 在分析表与表之间的业务关系时一定要建立 在某个业务意义基础上去分析。
1.2 & &数据模型分析
用户表user:
&&&&&&&& 记录了购买商品的用户信息
订单表:orders
&&&&&&&& 记录了用户所创建的订单(购买商品的订单)
订单明细表:orderdetail:
&&&&&&&& 记录了订单的详细信息即购买商品的信息
商品表:items
&&&&&&&& 记录了商品信息
表与表之间的业务关系:
&&&&&&&& 在分析表与表之间的业务关系时需要建立 在某个业务意义基础上去分析。
先分析数据级别之间有关系的表之间的业务关系:
usre和orders:
user----&orders:一个用户可以创建多个订单,一对多
orders---&user:一个订单只由一个用户创建,一对一
orders和orderdetail:
orders---》orderdetail:一个订单可以包括 多个订单明细,因为一个订单可以购买多个商品,每个商品的购买信息在orderdetail记录,一对多关系
orderdetail--& orders:一个订单明细只能包括在一个订单中,一对一
orderdetail和itesm:
orderdetail---》itesms:一个订单明细只对应一个商品信息,一对一
items--& orderdetail:一个商品可以包括在多个订单明细 ,一对多
再分析数据库级别没有关系的表之间是否有业务关系:
orders和items:
orders和items之间可以通过orderdetail表建立 关系。
2 & & &一对一查询
2.1&&&& 需求
查询订单信息,关联查询创建订单的用户信息
2.2&&&& resultType
2.2.1&&&& sql语句
确定查询的主表:订单表
确定查询的关联表:用户表
&&&&&&&& 关联查询使用内链接?还是外链接?
&&&&&&&& 由于orders表中有一个外键(user_id),通过外键关联查询用户表只能查询出一条记录,可以使用内链接。
& orders.*,
& USER.username,
& USER.sex,
& USER.address
WHERE orders.user_id = user.id
2.2.2 & & 创建pojo
将上边sql查询的结果映射到pojo中,pojo中必须包括所有查询列名。
原始的Orders.java不能映射全部字段,需要新创建的pojo。
创建 一个pojo继承包括查询字段较多的po类。
package com.dzq.mybatis.
public class OrdersCustom extends Orders {
public String getUsername() {
public void setUsername(String username) {
this.username =
public String getAddress() {
public void setAddress(String address) {
this.address =
2.2.3 & &&mapper.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"&
&!--命名空间,对sql进行分类管理,实现sql隔离 注意:使用mapper代理的方法开发,namespace就有特殊重要的作用 namespace等于mapper接口地址 --&
&mapper namespace="com.dzq.mybatis.mapper.OrdersMapperCustom"&
&!-- 查询订单,关联查询用户 --&
&select id="findOrdersUser"
resultType="com.dzq.mybatis.domain.OrdersCustom"&
user.username,
user.address
where orders.user_id = user.id
2.2.4 & &mapper.java
package com.dzq.mybatis.
import java.util.L
import com.dzq.mybatis.domain.OrdersC
public interface OrdersMapperCustom {
//查询订单,关联查询用户
public List&OrdersCustom& findOrdersUser()throws E
2.2.5 测试代码
package com.dzq.mybatis.
import java.io.InputS
import java.util.L
import org.apache.ibatis.io.R
import org.apache.ibatis.session.SqlS
import org.apache.ibatis.session.SqlSessionF
import org.apache.ibatis.session.SqlSessionFactoryB
import org.junit.B
import org.junit.T
import com.dzq.mybatis.domain.OrdersC
import com.dzq.mybatis.mapper.OrdersMapperC
public class OrdersMapperCustomTest {
private SqlSessionFactory sqlSessionF
public void setUp() throws Exception {
// 创建sqlSessionFactory
// mybatis配置文件
String resource = "SqlMapConfig.xml";
// 得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建会话工厂,传入mybatis的配置文件的信息
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
public void testFindOrdersUser() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建代理对象
OrdersMapperCustom ordersMapperCustom=sqlSession.getMapper(OrdersMapperCustom.class);
//调用mapper的方法
List&OrdersCustom&list=ordersMapperCustom.findOrdersUser();
System.out.println(list);
sqlSession.close();
2.3.2 & & 使用resultMap映射的思路
使用resultMap将查询结果中的订单信息映射到Orders对象中,在orders类中添加User属性,将关联查询出来的用户信息映射到orders对象中的user属性中。
2.3.3 & &需要Orders类中添加user属性
public User getUser() {
public void setUser(User user) {
this.user = }
2.3.4 & &mapper.xml
2.3.4.1&& & & & & 定义resultMap
&!-- 定义订单查询用户的resultMap 将整个查询结果映射到Orders中 --&
&resultMap type="com.dzq.mybatis.domain.Orders" id="OrdersUserResultMap"&
&!--配置映射的订单信息 --&
&!--id指定查询列中的唯一标识,订单信息中的唯一标识,如果有多个列组成唯一标识,就配置多个id column:数据库列属性 property:需要映射的pojo对象属性 --&
&id column="id" property="id" /&
&result column="user_id" property="userId" /&
&result column="number" property="number" /&
&result column="createtime" property="createtime" /&
&result column="note" property="note" /&
&!--配置映射关联的用户信息 --&
&!-- association:用于映射关联查询单个对象的信息 property:映射关联的用户信息到Orders上的那个属性 --&
&association property="user" javaType="com.dzq.mybatis.domain.User"&
&!-- id:关联查询用户的唯一标识 --&
&!-- column:用于指定唯一标识用户信息的列 javaType:映射到user的那个属性 --&
&id column="user_id" property="id" /&
&result column="username" property="username" /&
&result column="sex" property="sex" /&
&result column="address" property="address" /&
&/association&
&/resultMap&
2.3.4.2 & & & & & &statement定义
&!-- 查询订单,关联查询用户 ,使用resultMap --&
&select id="findOrdersUserResultMap" resultMap="OrdersUserResultMap"&
user.username,
user.address
where orders.user_id
2.3.5 mapper.java
//查询订单,关联查询用户,使用resultMap
public List&OrdersCustom& findOrdersUserResultMap() throws E
2.3.6 测试代码
public void testFindOrdersUserResultMap() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建代理对象
OrdersMapperCustom ordersMapperCustom=sqlSession.getMapper(OrdersMapperCustom.class);
//调用mapper的方法
List&Orders&list=ordersMapperCustom.findOrdersUserResultMap();
System.out.println(list);
sqlSession.close();
2.4 & resultType和resultMap实现一对一查询小结
实现一对一查询:
resultType:使用resultType实现较为简单,如果pojo中没有包括查询出来的列名,需要增加列名对应的属性,即可完成映射。
如果没有查询结果的特殊要求建议使用resultType。
resultMap:需要单独定义resultMap,实现有点麻烦,如果对查询结果有特殊的要求,使用resultMap可以完成将关联查询映射pojo的属性中。
resultMap可以实现延迟加载,resultType无法实现延迟加载。
3 & & &一对多查询
3.1&&&& 需求
查询订单及订单明细的信息。
3.2&&&& sql语句
确定主查询表:订单表
确定关联查询表:订单明细表
在一对一查询基础上添加订单明细表关联即可。
& orders.*,
& USER.username,
& USER.sex,
& USER.address,
&&orderdetail.id orderdetail_id,
& orderdetail.items_id,
& orderdetail.items_num,
& orderdetail.orders_id
& orderdetail
WHERE orders.user_id = user.id AND orderdetail.orders_id=orders.id
3.3&&&& 分析
使用resultType将上边的 查询结果映射到pojo中,订单信息的就是重复。
对orders映射不能出现重复记录。
在orders.java类中添加List&orderDetail& orderDetails属性。
最终会将订单信息映射到orders中,订单所对应的订单明细映射到orders中的orderDetails属性中。
映射成的orders记录数为两条(orders信息不重复)
每个orders中的orderDetails属性存储了该 订单所对应的订单明细。
3.4 & &在orders中添加list订单明细属性
private List&Orderdetail&
public List&Orderdetail& getOrderdetails() {
public void setOrderdetails(List&Orderdetail& orderdetails) {
this.orderdetails =
3.5 &&mapper.xml
&!-- 查询订单,关联查询用户 及订单明细使用resultMap --&
&select id="findOrdersAndOrderDetailResultMap" resultMap="OrdersAndOrderDetailResultMap"&
user.username,
user.address,
orderdetail.id orderdetail_id,
orderdetail.items_id,
orderdetail.items_num,
orderdetail.orders_id
orderdetail
where orders.user_id = user.id and orderdetail.orders_id=orders.id
3.6 & resultMap定义
&!-- 定义 查询订单,关联查询用户 及订单明细的resultMap 使用继承,就不用配置订单和用户的映射了 --&
&resultMap type="com.dzq.mybatis.domain.Orders" id="OrdersAndOrderDetailResultMap"
extends="OrdersUserResultMap"&
&!--订单信息 --&
&!-- 用户信息 --&
&!-- 使用继承,就不用配置订单和用户的映射了 --&
&!--订单详情信息 --&
&!-- 一个订单关联查询了多条明细 要使用 collection进行映射 collection:将关联查询的多条记录映射到集合对象中 property:将关联查询到的属性映射到pojo的那个属性中
ofType:映射的集合属性(list)中的pojo类型 --&
&collection property="orderdetails" ofType="Orderdetail"&
&!-- id:映射的集合属性(list)中的pojo的唯一标识 column:数据库的列 property:映射到的pojo的属性 --&
&id column="orderdetail_id" property="id" /&
&result column="items_id" property="itemsId" /&
&result column="items_num" property="itemsNum" /&
&result column="orders_id" property="ordersId" /&
&/collection&
&/resultMap&
3.7mapper.java
//查询订单及订单明细关联用户
public List&Orders& findOrdersAndOrderDetailResultMap() throws E
3.8测试代码
public void testFindOrdersAndOrderDetailResultMap() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建代理对象
OrdersMapperCustom ordersMapperCustom=sqlSession.getMapper(OrdersMapperCustom.class);
//调用mapper的方法
List&Orders&list=ordersMapperCustom.findOrdersAndOrderDetailResultMap();
System.out.println(list);
sqlSession.close();
3.9 & &小结
mybatis使用resultMap的collection对关联查询的多条记录映射到一个list集合属性中。
使用resultType实现:
将订单明细映射到orders中的orderdetails中,需要自己处理,使用双重循环遍历,去掉重复记录,将订单明细放在orderdetails中。
4 & & 多对多查询
4.1&&&& 需求
查询用户及用户购买商品信息。
4.2&&&& sql语句
查询主表是:用户表
关联表:由于用户和商品没有直接关联,通过订单和订单明细进行关联,所以关联表:
orders、orderdetail、items
& orders.*,
& USER.username,
& USER.sex,
& USER.address,
& orderdetail.id orderdetail_id,
& orderdetail.items_id,
& orderdetail.items_num,
& orderdetail.orders_id,
& items.name items_name,
& items.detail items_detail,
& items.price items_price
& orderdetail,
WHERE orders.user_id = user.id AND orderdetail.orders_id=orders.id AND orderdetail.items_id = items.id
4.3&&&& 映射思路
将用户信息映射到user中。
在user类中添加订单列表属性List&Orders& orderslist,将用户创建的订单映射到orderslist
在Orders中添加订单明细列表属性List&OrderDetail&orderdetials,将订单的明细映射到orderdetials
在OrderDetail中添加Items属性,将订单明细所对应的商品映射到Items
4.4&&&& mapper.xml
&!-- 查询用户及购买商品信息 --&
&select id="findUserAndItemsResultMap" resultMap="UserAndItemsResultMap"&
user.username,
user.address,
orderdetail.id
orderdetail_id,
orderdetail.items_id,
orderdetail.items_num,
orderdetail.orders_id,
items.name items_name,
items.detail items_detail,
items.price items_price
orderdetail,
orders.user_id = user.id and orderdetail.orders_id=orders.id and
orderdetail.items_id = items.id
4.5 & & resultMap定义
&!--多对多 --&
&!-- 查询用户及购买的商品的ResultMap --&
&resultMap type="com.dzq.mybatis.domain.User" id="UserAndItemsResultMap"&
&!-- 用户信息 --&
&id column="user_id" property="id" /&
&result column="username" property="username" /&
&result column="sex" property="sex" /&
&result column="address" property="address" /&
&!-- 订单信息 一个用户对应多个订单,使用collection --&
&collection property="list" ofType="com.dzq.mybatis.domain.Orders"&
&id column="id" property="id" /&
&result column="user_id" property="userId" /&
&result column="number" property="number" /&
&result column="createtime" property="createtime" /&
&result column="note" property="note" /&
&!-- 订单明细,一个订单包括多个明细 --&
&collection property="orderdetails" ofType="com.dzq.mybatis.domain.Orderdetail"&
&id column="orderdetail_id" property="id" /&
&result column="items_id" property="itemsId" /&
&result column="items_num" property="itemsNum" /&
&result column="orders_id" property="ordersId" /&
&!-- 一个订单明细对应一个商品 --&
&association property="items" javaType="com.dzq.mybatis.domain.Items"&
&id column="items_id" property="id" /&
&result column="items_name" property="name" /&
&result column="items_detail" property="detail" /&
&result column="items_price" property="price" /&
&/association&
&/collection&
&/collection&
&/resultMap&
4.6 & &&mapper.java
public List&User& findUserAndItemsResultMap() throws E
4.7测试代码:
public void testFindUserAndItemsResultMap() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建代理对象
OrdersMapperCustom ordersMapperCustom=sqlSession.getMapper(OrdersMapperCustom.class);
//调用mapper的方法
List&User&list=ordersMapperCustom.findUserAndItemsResultMap();
System.out.println(list);
sqlSession.close();
4.8 &多对多查询总结
将查询用户购买的商品信息明细清单,(用户名、用户地址、购买商品名称、购买商品时间、购买商品数量)
针对上边的需求就使用resultType将查询到的记录映射到一个扩展的pojo中,很简单实现明细清单的功能。
一对多是多对多的特例,如下需求:
查询用户购买的商品信息,用户和商品的关系是多对多关系。
查询字段:用户账号、用户名称、用户性别、商品名称、商品价格(最常见)
企业开发中常见明细列表,用户购买商品明细列表,
使用resultType将上边查询列映射到pojo输出。
查询字段:用户账号、用户名称、购买商品数量、商品明细(鼠标移上显示明细)
使用resultMap将用户购买的商品明细列表映射到user对象中。
使用resultMap是针对那些对查询结果映射有特殊要求的功能,,比如特殊要求映射成list中包括 多个list。
5 & & & resultMap总结
resultType:
&&&&&&&& 将查询结果按照sql列名pojo属性名一致性映射到pojo中。
&&&&&&&& 常见一些明细记录的展示,比如用户购买商品明细,将关联查询信息全部展示在页面时,此时可直接使用resultType将每一条记录映射到pojo中,在前端页面遍历list(list中是pojo)即可。
resultMap:
&&&&&&&& 使用association和collection完成一对一和一对多高级映射(对结果有特殊的映射要求)。
association:
&&&&&&&& 将关联查询信息映射到一个pojo对象中。
&&&&&&&& 为了方便查询关联信息可以使用association将关联订单信息映射为用户对象的pojo属性中,比如:查询订单及关联用户信息。
&&&&&&&& 使用resultType无法将查询结果映射到pojo对象的pojo属性中,根据对结果集查询遍历的需要选择使用resultType还是resultMap。
collection:
&&&&&&&& 将关联查询信息映射到一个list集合中。
&&&&&&&& 为了方便查询遍历关联信息可以使用collection将关联信息映射到list集合中,比如:查询用户权限范围模块及模块下的菜单,可使用collection将模块映射到模块list中,将菜单列表映射到模块对象的菜单list属性中,这样的作的目的也是方便对查询结果集进行遍历查询。
&&&&&&&& 如果使用resultType无法将查询结果映射到list集合中。
6 & &延迟加载
6.1&&&& 什么是延迟加载
resultMap可以实现高级映射(使用association、collection实现一对一及一对多映射),association、collection具备延迟加载功能。
如果查询订单并且关联查询用户信息。如果先查询订单信息即可满足要求,当我们需要查询用户信息时再查询用户信息。把对用户信息的按需去查询就是延迟加载。
延迟加载:先从单表查询、需要时再从关联表去关联查询,大大提高 数据库性能,因为查询单表要比关联查询多张表速度要快。
6.2 & & 使用association实现延迟加载
6.2.1&&&& 需求
查询订单并且关联查询用户信息
6.2.2&&&& mapper.xml
需要定义两个mapper的方法对应的statement。
1、只查询订单信息
SELECT * FROM orders
在查询订单的statement中使用association去延迟加载(执行)下边的satatement(关联查询用户信息)
&!-- 查询订单,关联查询用户,用户信息,需要延迟加载 --&
&select id="findOrdersUserLazyLoading" resultMap="findOrdersUserLazyLoadingResultMap"&
SELECT * FROM
2、关联查询用户信息
&&&&&&&& 通过上边查询到的订单信息中user_id去关联查询用户信息
&&&&&&&& 使用UserMapper.xml中的findUserById
&select id="findUserById" parameterType="int" resultType="com.dzq.mybatis.domain.User"&
select * from user where id=#{id}
上边先去执行findOrdersUserLazyLoading,当需要去查询用户的时候再去执行findUserById,通过resultMap的定义将延迟加载执行配置起来。
6.2.3&&&& 延迟加载resultMap
&!-- 这是延迟加载的resultMap --&
&resultMap type="com.dzq.mybatis.domain.Orders" id="findOrdersUserLazyLoadingResultMap"&
&!--对订单细信息进行映射配置 --&
&id column="id" property="id" /&
&result column="user_id" property="userId" /&
&result column="number" property="number" /&
&result column="createtime" property="createtime" /&
&result column="note" property="note" /&
&!-- 实现对用户信息延迟加载
select:指定延迟加载所需执行的statement的id
要使用userMapper。xml中的findUserById完成用户信息查询,如果findUserById不在本mapper中,加上namespace
column:关联用户信息的列
&association property="user" javaType="com.dzq.mybatis.domain.User" select="com.dzq.mybatis.mapper.UserMapper.findUserById" column="user_id"&
&/association&
&/resultMap&
6.2.4 & &&mapper.java
//查询订单关联查询用户,用户信息延迟加载
public List&Orders&findOrdersUserLazyLoading() throws E
6.2.5 & & 测试
6.2.5.1 & & & & & 测试思路:
1、执行上边mapper方法(findOrdersUserLazyLoading),内部去调用cn.itcast.mybatis.mapper.OrdersMapperCustom中的findOrdersUserLazyLoading只查询orders信息(单表)。
2、在程序中去遍历上一步骤查询出的List&Orders&,当我们调用Orders中的getUser方法时,开始进行延迟加载。
3、延迟加载,去调用UserMapper.xml中findUserbyId这个方法获取用户信息。
6.2.5.2 & & & 延迟加载配置
mybatis默认没有开启延迟加载,需要在SqlMapConfig.xml中setting配置。
在mybatis核心配置文件中配置:
lazyLoadingEnabled、aggressiveLazyLoading
在SqlMapConfig.xml中配置:
&!-- 全局配置参数 --&
&settings&
&!-- 打开延迟加载的开关 --&
&setting name="lazyLoadingEnabled" value="true"/&
将积极加载改为消极加载,即按需加载--&
&setting name="aggressiveLazyLoading" value="false"/&
&/settings&
6.2.5.3 & & & & & & 测试代码
//查询订单,关联查询用户,用户信息延迟加载
public void testfindOrdersUserLazyLoading() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建代理对象
OrdersMapperCustom ordersMapperCustom=sqlSession.getMapper(OrdersMapperCustom.class);
//调用mapper的方法
//查询订单信息
List&Orders&list=ordersMapperCustom.findOrdersUserLazyLoading();
//遍历上边的订单列表
for(Orders order:list){
//执行getUser实现按需加载
User user=order.getUser();
System.out.println(user.getUsername());
System.out.println(list);
sqlSession.close();
一开始只有一条查询单表的sql,在执行到getUser时
6.2.6 & & 延迟加载思考
不使用mybatis提供的association及collection中的延迟加载功能,如何实现延迟加载??
实现方法如下:
定义两个mapper方法:
1、查询订单列表
2、根据用户id查询用户信息
实现思路:
先去查询第一个mapper方法,获取订单信息列表
在程序中(service),按需去调用第二个mapper方法去查询用户信息。
使用延迟加载方法,先去查询简单的sql(最好单表,也可以关联查询),再去按需要加载关联查询的其它信息。
7 & & &查询缓存
1.1&&&& 什么是查询缓存
mybatis提供查询缓存,用于减轻数据压力,提高数据库性能。
mybaits提供一级缓存,和二级缓存。
一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。
二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
为什么要用缓存?
如果缓存中有数据就不用从数据库中获取,大大提高系统性能。
7.1&&&& 一级缓存
7.1.1&&&& 一级缓存工作原理
第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户信息。
得到用户信息,将用户信息存储到一级缓存中。
如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。
7.1.2 & & 一级缓存测试
mybatis默认支持一级缓存,不需要在配置文件去配置。
按照上边一级缓存原理步骤去测试。
public void testCache1() throws Exception{
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建代理对象
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
//下边查询使用一个sqlSession
//第一次发起请求,查询id为1的用户
User user1=userMapper.findUserById(1);
System.out.println(user1.getUsername());
//第二次发起请求,查询id为1的用户
User user2=userMapper.findUserById(1);
System.out.println(user2.getUsername());
public void testCache1() throws Exception{
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建代理对象
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
//下边查询使用一个sqlSession
//第一次发起请求,查询id为1的用户
User user1=userMapper.findUserById(1);
System.out.println(user1.getUsername());
//如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
//创建更新对象,更新user1
user1.setUsername("哈哈哈哈");
userMapper.updateUser(user1);
//执行commit操作,才会清空缓存
//第二次发起请求,查询id为1的用户
User user2=userMapper.findUserById(1);
System.out.println(user2.getUsername());
commit会清空缓存
7.2.3 & &一级缓存应用
正式开发,是将mybatis和spring进行整合开发,事务控制在service中。
一个service方法中包括 很多mapper方法调用。
&&&&&&&& //开始执行时,开启事务,创建SqlSession对象
&&&&&&&& //第一次调用mapper的方法findUserById(1)
&&&&&&&& //第二次调用mapper的方法findUserById(1),从一级缓存中取数据
&&&&&&&& //方法结束,sqlSession关闭
如果是执行两次service调用查询相同 的用户信息,不走一级缓存,因为session方法结束,sqlSession就关闭,一级缓存就清空。
7.3 & & 二级缓存
7.3.1&&&& 原理
首先开启mybatis的二级缓存。
sqlSession1去查询用户id为1的用户信息,查询到用户信息会将查询数据存储到二级缓存中。
如果SqlSession3去执行相同 mapper下sql,执行commit提交,清空该 mapper下的二级缓存区域的数据。
sqlSession2去查询用户id为1的用户信息,去缓存中找是否存在数据,如果存在直接从缓存中取出数据。
二级缓存与一级缓存区别,二级缓存的范围更大,多个sqlSession可以共享一个UserMapper的二级缓存区域。
UserMapper有一个二级缓存区域(按namespace分) ,其它mapper也有自己的二级缓存区域(按namespace分)。
每一个namespace的mapper都有一个二缓存区域,两个mapper的namespace如果相同,这两个mapper执行sql查询到数据将存在相同 的二级缓存区域中。
7.3.2 & &开启二级缓存
mybaits的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,还要在具体的mapper.xml中开启二级缓存。
在核心配置文件SqlMapConfig.xml中加入:
&!-- 二级缓存 --&
&setting name="cacheEnabled" value="true"/&
在UserMapper.xml中开启二缓存,UserMapper.xml下的sql执行完成会存储到它的缓存区域(HashMap)。
&!-- 开启本mapper的namespace下的二级缓存 --&
7.3.3 & 调用pojo类实现序列化接口
public class User
implements Serializable{
// 属性名和数据库表的字段对应
private int
private S// 用户姓名
private S// 性别
private D// 生日
private S// 地址
private List&Orders&
public int getId() {
为了将缓存数据取出执行反序列化操作,因为二级缓存数据存储介质多种多样,不一样在内存。
7.3.4 & & 测试方法
//二级缓存测试
public void testCache2() throws Exception{
SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
SqlSession sqlSession3 = sqlSessionFactory.openSession();
//创建代理对象
UserMapper userMapper1=sqlSession1.getMapper(UserMapper.class);
//第一次发起请求,查询id为1的用户
User user1=userMapper1.findUserById(1);
System.out.println(user1.getUsername());
//这里的sqlSession要是不关闭,缓存写不到二级缓存区域
sqlSession1.close();
UserMapper userMapper2=sqlSession2.getMapper(UserMapper.class);
//使用sqlSession3执行commit操作
UserMapper userMapper3=sqlSession3.getMapper(UserMapper.class);
User user3=userMapper3.findUserById(1);
user3.setUsername("嘻嘻嘻嘻");
userMapper3.updateUser(user3);
sqlSession3.close();
/*//如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
//创建更新对象,更新user1
user1.setUsername("哈哈哈哈");
userMapper.updateUser(user1);
//执行commit操作,才会清空缓存
//第二次发起请求,查询id为1的用户
User user2=userMapper2.findUserById(1);
System.out.println(user2.getUsername());
sqlSession2.close();
7.3.5 & & useCache配置
&禁用以后,会每次都从数据库取数据
在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存。
&select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false"&
总结:针对每次查询都需要最新的数据sql,要设置成useCache=false,禁用二级缓存。
7.3.6 & &刷新缓存(就是清空缓存)
在mapper的同一个namespace中,如果有其它insert、update、delete操作数据后需要刷新缓存,如果不执行刷新缓存会出现脏读。
&设置statement配置中的flushCache="true"&属性,默认情况下为true即刷新缓存,如果改成false则不会刷新。使用缓存时如果手动修改数据库表中的查询数据会出现脏读。
&insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" flushCache="true"&
总结:一般下执行完commit操作都需要刷新缓存,flushCache=true表示刷新缓存,这样可以避免数据库脏读。
7.4 & & mybatis整合ehcache
ehcache是一个分布式缓存框架。
7.4.1 & 分布缓存
我们系统为了提高系统并发,性能、一般对系统进行分布式部署(集群部署方式)
不使用分布缓存,缓存的数据在各各服务单独存储,不方便系统 开发。所以要使用分布式缓存对缓存数据进行集中管理。
mybatis无法实现分布式缓存,需要和其它分布式缓存框架进行整合。
7.4.2 & 整合方法(掌握)
mybatis提供了一个cache接口,如果要实现自己的缓存逻辑,实现cache接口开发即可。
mybatis和ehcache整合,mybatis和ehcache整合包中提供了一个cache接口的实现类。
mybatis默认实现cache类是:
7.4.3 & &加入ehcache包
7.4.4 & &整合ehcache
&!-- 开启本mapper的namespace下的二级缓存
type:指定接口实现类型,mybatis默认使用PerpetualCache
要和ehcache整合,需要配置type为ehcache的实现类
&cache type="org.mybatis.caches.ehcache.EhcacheCache"/&
7.4.5 & 加入ehcache的配置文件
在classpath下配置ehcache.xml
&ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"&
&diskStore path="D:\myworkspace\ehcache" /&
&defaultCache
maxElementsInMemory="1000"
maxElementsOnDisk=""
eternal="false"
overflowToDisk="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"&
&/defaultCache&
&/ehcache&
7.5 &二级应用场景
对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访问速度,业务场景比如:耗时较高的统计分析sql、电话账单查询sql等。
&&&&&&&& 实现方法如下:通过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushInterval,比如设置为30分钟、60分钟、24小时等,根据需求而定。
7.6 & 二级缓存局限性
&&&&&&&& mybatis二级缓存对细粒度的数据级别的缓存实现不好,比如如下需求:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品信息,此时如果使用mybatis的二级缓存就无法实现当一个商品变化时只刷新该商品的缓存信息而不刷新其它商品的信息,因为mybaits的二级缓存区域以mapper为单位划分,当一个商品信息变化会将所有商品信息的缓存数据全部清空。解决此类问题需要在业务层根据需求对数据有针对性缓存。
8 & & & spring和mybatis整合
8.1&&&& 整合思路
需要spring通过单例方式管理SqlSessionFactory。
spring和mybatis整合生成代理对象,使用SqlSessionFactory创建SqlSession。(spring和mybatis整合自动完成)
持久层的mapper都需要由spring进行管理。
8.2&&&& 整合环境
创建一个新的java工程(接近实际开发的工程结构)
mybatis3.2.7的jar包
spring3.2.0的jar包
mybatis和spring的整合包:早期ibatis和spring整合是由spring官方提供,mybatis和spring整合由mybatis提供。
全部jar包(包括springmvc)
8.3 & & sqlSessionFactory
在applicationContext.xml配置sqlSessionFactory和数据源
sqlSessionFactory在mybatis和spring的整合包下。
&beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd "&
&!-- 加载配置文件 --&
&context:property-placeholder location="classpath:db.properties" /&
&!-- 配置数据源,使用dbcp --&
&bean id="dataSource" class="mons.dbcp.BasicDataSource"
destroy-method="close"&
&property name="driverClassName" value="${jdbc.driver}" /&
&property name="url" value="${jdbc.url}" /&
&property name="username" value="${jdbc.username}" /&
&property name="password" value="${jdbc.password}" /&
&property name="maxActive" value="10" /&
&property name="maxIdle" value="5" /&
&!-- sqlSesssionFactory --&
&bean id="SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"&
&!--加载mybatis的配置文件 --&
&property name="configLocation" value="mybatis/SqlMapConfig.xml" /&
&!--配置数据源 --&
&property name="dataSource" ref="dataSource" /&
8.4 & & 原始dao开发(和spring整合后)
8.4.1 & &User.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"&
&!--命名空间,对sql进行分类管理,实现sql隔离 注意:使用mapper代理的方法开发,namespace就有特殊重要的作用 --&
&mapper namespace="test"&
&!-- 在映射文件中配置很多sql语句 --&
&!-- 通过id查询用户表的记录 --&
&!--通过select执行数据库的查询
id:标识映射文件中的sql,称为statemen的id 将sql语句封装到mappedstatement对象中
#{}:表示占位符
parameterType:指定输入参数类型,这里指定int型
{id}:其中的id表示接收输入参数,如果输入参数是简单类型,#{}中参数名可以任意,可以是value或者其他名称
resultType:指定sql输出结果所映射的java对象类型,select指定resultType将单条记录所映射成的java对象
&select id="findUserById" parameterType="int" resultType="com.dzq.ssm.po"&
select * from user where id=#{id}
在SqlMapconfig.xml中加载User.xml
&mapper resource="sqlmap/User.xml" /&
8.4.2 & & dao(实现类继承SqlSessionDaoSupport)
public interface UserDao {
// 根据id查询用户信息
public User findUserById(int id) throws E
dao接口实现类需要注入SqlSessoinFactory,通过spring进行注入。
这里spring声明配置方式,配置dao的bean:
让UserDaoImpl实现类继承SqlSessionDaoSupport
package com.dzq.ssm.
import org.apache.ibatis.session.SqlS
import org.mybatis.spring.support.SqlSessionDaoS
import com.dzq.ssm.po.U
public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao
public User findUserById(int id) throws Exception {
//继承了SqlSessionDaoSupport,通过这种方法得到sqlsession
SqlSession sqlSession = this.getSqlSession();
User user = sqlSession.selectOne("test.findUserById", id);
8.4.3 & &配置dao
在applicationContext.xml中配置dao。
&!-- 原始dao接口 --&
&bean id="userDao" class="com.dzq.ssm.dao.UserDaoImpl"&
&property name="SqlSessionFactory" ref="SqlSessionFactory"/&
8.4.4 & &测试程序
public class UserDaoImplTest {
private ApplicationContext applicationC
//在这个方法中得到spring的容器
public void setUp() throws Exception {
applicationContext=new ClassPathXmlApplicationContext("classpath:spring/applicationContext.xml");
public void testFindUserById() throws Exception {
UserDao userDao=(UserDao) applicationContext.getBean("userDao");
//调用userDao的方法
User user=userDao.findUserById(1);
System.out.println(user.getUsername());
8.5 & &mapper代理开发
8.5.1&&&& mapper.xml和mapper.java
mapper.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"&
&!--命名空间,对sql进行分类管理,实现sql隔离 注意:使用mapper代理的方法开发,namespace就有特殊重要的作用 namespace等于mapper接口地址 --&
&mapper namespace="com.dzq.ssm.mapper.UserMapper"&
&select id="findUserById" parameterType="int"
resultType="com.dzq.mybatis.domain.User"&
select * from user where id=#{id}
mapper.java
package com.dzq.ssm.
import com.dzq.ssm.po.U
public interface UserMapper {
// 根据id查询用户信息
public User findUserById(int id) throws E
8.5.2 & &通过MapperFactoryBean创建代理对象
&!-- mapper的配置 --&
MapperFactoryBean:根据mapper接口生成代理对象
&bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"&
&!-- mapperInterface指定mapper j接口 --&
&property name="mapperInterface" value="com.dzq.ssm.mapper.UserMapper"/&
&property name="SqlSessionFactory" ref="SqlSessionFactory"/&
此方法问题:
需要针对每个mapper进行配置,麻烦。
8.5.3 & 通过MapperScannerConfigurer进行mapper扫描(建议使用)
&!-- mapper的批量扫描 ,从mapper的包中扫描出mapper的接口,自动创建代理对象并且在spring容器中注册
遵循规范:将mapper的接口类名和mapper。xml的名保持一致,并且在同一个目录中
自动扫描mapper出来的bean的id 为mapper类名首字母小写
&bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"&
&!--指定扫描的包名
如果扫描多个包,每个包之间使用半角逗号分隔
&property name="basePackage" value="com.dzq.ssm.mapper"/&
&property name="sqlSessionFactoryBeanName" value="SqlSessionFactory"/&
8.5.4 & & 测试代码
package com.dzq.ssm.
import org.junit.B
import org.junit.T
import org.springframework.context.ApplicationC
import org.springframework.context.support.ClassPathXmlApplicationC
import com.dzq.ssm.mapper.UserM
import com.dzq.ssm.po.U
public class UserMapperTest {
private ApplicationContext applicationC
//在这个方法中得到spring的容器
public void setUp() throws Exception {
applicationContext=new ClassPathXmlApplicationContext("classpath:spring/applicationContext.xml");
public void testFindUserById() throws Exception {
UserMapper userMapper=(UserMapper) applicationContext.getBean("userMapper");
User user=userMapper.findUserById(1);
System.out.println(user.getUsername());
9 & & &逆向工程
9.1&&&& 什么是逆向工程
mybaits需要程序员自己编写sql语句,mybatis官方提供逆向工程 可以针对单表自动生成mybatis执行所需要的代码(mapper.java,mapper.xml、po..)
企业实际开发中,常用的逆向工程方式:
由数据库的表生成java代码。
9.2&&&& 下载逆向工程
9.3 & & 使用方法(会用)
9.3.1&&&& 运行逆向工程
建议使用java程序方式,不依赖开发工具。
9.3.2 & &生成代码配置文件
&?xml version="1.0" encoding="UTF-8"?&
&!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"&
&generatorConfiguration&
&context id="testTables" targetRuntime="MyBatis3"&
&commentGenerator&
&!-- 是否去除自动生成的注释 true:是 : false:否 --&
&property name="suppressAllComments" value="true" /&
&/commentGenerator&
&!--数据库连接的信息:驱动类、连接地址、用户名、密码 --&
&jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis" userId="root"
password="mysql"&
&/jdbcConnection&
&!-- &jdbcConnection driverClass="oracle.jdbc.OracleDriver"
connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:yycg"
userId="yycg"
password="yycg"&
&/jdbcConnection& --&
&!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL 和
NUMERIC 类型解析为java.math.BigDecimal --&
&javaTypeResolver&
&property name="forceBigDecimals" value="false" /&
&/javaTypeResolver&
&!-- targetProject:生成PO类的位置 --&
&javaModelGenerator targetPackage="cn.itcast.ssm.po"
targetProject=".\src"&
&!-- enableSubPackages:是否让schema作为包的后缀 --&
&property name="enableSubPackages" value="false" /&
&!-- 从数据库返回的值被清理前后的空格 --&
&property name="trimStrings" value="true" /&
&/javaModelGenerator&
&!-- targetProject:mapper映射文件生成的位置 --&
&sqlMapGenerator targetPackage="cn.itcast.ssm.mapper"
targetProject=".\src"&
&!-- enableSubPackages:是否让schema作为包的后缀 --&
&property name="enableSubPackages" value="false" /&
&/sqlMapGenerator&
&!-- targetPackage:mapper接口生成的位置 --&
&javaClientGenerator type="XMLMAPPER"
targetPackage="cn.itcast.ssm.mapper"
targetProject=".\src"&
&!-- enableSubPackages:是否让schema作为包的后缀 --&
&property name="enableSubPackages" value="false" /&
&/javaClientGenerator&
&!-- 指定数据库表 --&
&table tableName="items"&&/table&
&table tableName="orders"&&/table&
&table tableName="orderdetail"&&/table&
&table tableName="user"&&/table&
&/context&
&/generatorConfiguration&
9.3.3 & 执行生成程序
List&String& warnings = new ArrayList&String&();
boolean overwrite = true;
File configFile = new File("generatorConfig.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
运行之前:
生成后的代码:
9.3.4 & &使用生成的代码
需要将生成工程中所生成的代码拷贝到自己的工程中。
测试ItemsMapper中的方法
//自定义条件查询
public void testSelectByExample() {
ItemsExample itemsExample = new ItemsExample();
//通过criteria构造查询条件
ItemsExample.Criteria criteria = itemsExample.createCriteria();
criteria.andNameEqualTo("笔记本3");
//可能返回多条记录
List&Items& list = itemsMapper.selectByExample(itemsExample);
System.out.println(list);
//根据主键查询
public void testSelectByPrimaryKey() {
Items items = itemsMapper.selectByPrimaryKey(1);
System.out.println(items);
public void testInsert() {
//构造 items对象
Items items = new Items();
items.setName("手机");
items.setPrice(999f);
itemsMapper.insert(items);
//更新数据
public void testUpdateByPrimaryKey() {
//对所有字段进行更新,需要先查询出来再更新
Items items = itemsMapper.selectByPrimaryKey(1);
items.setName("水杯");
itemsMapper.updateByPrimaryKey(items);
//如果传入字段不空为才更新,在批量更新中使用此方法,不需要先查询再更新
//itemsMapper.updateByPrimaryKeySelective(record);
阅读(...) 评论()

我要回帖

更多关于 服务号和订阅号哪个好 的文章

 

随机推荐