您的位置:首页 > 编程语言 > Java开发

myBatis入门学习_下

2018-01-07 22:41 295 查看
myBatis入门学习_下:

本章主要讲动态sql,关联查询,spring整合,,如果是初次学习myBatis的同学,请先阅读myBatis入门学习_上

话不多说,上来就是一个需求,惊不惊喜,意不意外 嘿嘿

根据用户名查询用户信息,查询条件放到QueryVo的user属性中。

友情提示

- 需要数据的小伙伴请点击myBatis入门学习_上,获取数据库数据…

- 然后粗略的介绍一下Vo,其实就是valueObject的简写,因为select 参数类型只能有一个,我们就是用vo来做数据的存储的…

好了..我们创建一个queryVo

package cn.mybatis.pojo;

public class QueryVo {

//创建一个user对象
private User user;

public void setUser(User user) {
this.user = user;
}
}


然后在配置文件里写sql语句…

<select id="usernameLikeFind" parameterType="cn.mybatis.pojo.QueryVo" resultType="cn.mybatis.pojo.User">
<!--使用ognl从对象中取属性值,如果是包装对象可以使用【属性.XXX.XXX】来取内容的属性-->
select * from user where username like '%${user.username}%'
</select>


这里使用的是mapper接口方式写代码,就不写实体类了,

userMapper 接口新增方法

public List<User> usernameLikeFind(QueryVo vo);


编写测试代码

SqlSessionFactory factory;
InputStream stream;

@Before
public void createSqlSessionFactory(){
String resources = "mybatisConfig.xml";

//Resources.getResourceAsStream(resources)  这句代码的意思就是查找classpath目录下的mybatisConfig.xml文件
try {
stream = Resources.getResourceAsStream(resources);
}catch (Exception e){

}

SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//获取工厂
factory = builder.build(stream);
}

因为没有整合spring,所以我们需要先使用该该方法初始化factory,

//测试代码
@Test
public void test_fun03(){
//获取session
SqlSession session = factory.openSession();
UserMapper mapper = session.getMapper(UserMapper.class);
User user = new User();
user.setUsername("小");

QueryVo queryVo = new QueryVo();
queryVo.setUser(user);
List<User> users = mapper.usernameLikeFind(queryVo);

System.out.println("user="+users);
session.close();
}


查询结果如下,



其实动态if啥的没啥好讲的,,看几个案例就懂了,

if语句

小需求 : action 层 传3个值过来,姓名 地址 性别 值可能为null,null 值就不加入查询sql语句中,

有7种可能性,如果不使用动态if,那么我们就得写七条sql,,那不是得累死……

有的小伙伴估计要怼我了,,明明就是六种,你硬要说成七种,你是不是傻,,,还有一种可能是就3个值都是null,那就是查询所有

开始写代码把…………先写sql

<select id="queryUserByUsernameAndAddressAndSex" parameterType="cn.mybatis.pojo.User" resultType="cn.mybatis.pojo.User">
<!--基础sql语句-->
select * from user WHERE  1 = 1
<!--动态拼接sql -->
<if test="username != null">
and username like '%${username}%'
</if>

<if test="address != null">
and address like '%${address}%'
</if>

<if test="sex != null">
and sex = '#{sex}'
</if>
</select>


那个,,, if 有什么作用就不用我来讲了把…….如果真不懂,,那我也没辙了….

接口新增方法…

public List<User> queryUserByUsernameAndAddressAndSex(User user);


测试代码

先测试一波不加参数的,
@Test
public void test_fun04(){
//获取session
SqlSession session = factory.openSession();
UserMapper mapper = session.getMapper(UserMapper.class);
User user = new User();

List<User> users = mapper.queryUserByUsernameAndAddressAndSex(user);

System.out.println("user="+users);
session.close();
}


运行结果是没问题的,



这时可能就有同学不耐烦了,写sql还要加上 where 1 = 1 ,那么麻烦,不学了
4000

别急,myBatis 给我们提供了标签,加上了就不用写了,不信的话我去试试

<select id="queryUserByUsernameAndAddressAndSex" parameterType="cn.mybatis.pojo.User" resultType="cn.mybatis.pojo.User">
<!--基础sql语句-->
select * from user
<where>
<!--动态拼接sql -->
<if test="username != null">
and username like '%${username}%'
</if>

<if test="address != null">
and address like '%${address}%'
</if>

<if test="sex != null">
and sex = '#{sex}'
</if>
</where>
</select>


然后我这次再加个条件测试一波

@Test
public void test_fun04(){
//获取session
SqlSession session = factory.openSession();
UserMapper mapper = session.getMapper(UserMapper.class);
User user = new User();

user.setSex("1");
List<User> users = mapper.queryUserByUsernameAndAddressAndSex(user);

System.out.println("user="+users);
session.close();
}




哎呀,,出问题了,,,,但是好像不是标签的问题,去瞄一下sql语句,

<if test="sex != null">
and sex = '#{sex}'
</if>


其实使用 #{} 是不能使用引号的,,

然后去掉引号,再测试,



foreach语句

现在action 层又有需求了,传过来一个list集合,要求我们查询id = list里用户id的用户订单,

我们先在脑子意淫一下sql 语句

select * from 订单 where 订单.用户id in(a,b,c);

有小伙伴肯定跟我开始想一块了, 把 list遍历一下,然后拼接成字符串 a,b,c 然后把 a,b,c 当成一个参数传过去 /坏笑,这种事想想就好了啊 ahhh

我们在Vo对象里写一个List属性,传的话就传一个Vo过去,,

private List<Integer> users;

public void setUsers(List<Integer> users) {
this.users = users;
}


然后我们来编写sql

<select id="findUserByOrder_uid" resultType="cn.mybatis.pojo.User" parameterType="cn.mybatis.pojo.QueryVo">
select * from user u,orders o where 1 = 1
<!--   (,)     -->
<foreach collection="users" open="and u.id in (" close=")" item="uid" separator=",">
#{uid}
</foreach>
</select>


嘿嘿,看傻了把, 我来解释一下把

collection=”users”的意思是 遍历 cn.mybatis.pojo.QueryVo 对象里的 users属性,

open=”(” 循环开始符号,

close=”)” 循环结束符号,

item=”uid” 循环的值

separator=”,” 分割符

假如只循环二次 , 一开始产生一个”and id in (“符号,此时 sql语句是这样的

select * from orders o,user u where 1 = 1 and u.id in (

然后拿到值 uid 拼接到sql中去后,sql 语句是这样的

select * from orders o,user u where 1 = 1 and u.id in ( a

然后结束第一次循环,开始第二次,然后sql语句是这样的

select * from orders o,user u where 1 = 1 and u.id in ( a ,

然后又拿到值

select * from orders o,user u where 1 = 1 and u.id in ( a ,b

最后,循环完毕,sql 语句是这样的

select * from orders o,user u where 1 = 1 and id u.in ( a ,b)

接口添加方法

public List<User> findUserByOrder_uid(QueryVo vo);


我们写测试代码测试一下

@Test
public void test_fun05(){
//获取session
SqlSession session = factory.openSession();
UserMapper mapper = session.getMapper(UserMapper.class);

List<Integer> list = Arrays.asList(1, 10, 3);
QueryVo queryVo = new QueryVo();
queryVo.setUsers(list);
List<Integer> users = mapper.findUserByOrder_uid(queryVo);

System.out.println("user="+users);
session.close();
}


看看生成的sql语句



sql 片段

我们接下来讲讲sql片段把,,,sql片段其实就是把共性代码抽取出来,然后一起分享使用

抽取代码
<sql id="selectXin" >
select *
</sql>

<select id="findUserByOrder_uid" resultType="cn.mybatis.pojo.User" parameterType="cn.mybatis.pojo.QueryVo">
使用抽取部分
<include refid="selectXin" /> from user u,orders o where 1 = 1
<!--   (,)     -->
<foreach collection="users" open="and u.id in (" close=")" item="uid" separator=",">
#{uid}
</foreach>
</select>


代码测试

@Test
public void test_fun05(){
//获取session
SqlSession session = factory.openSession();
UserMapper mapper = session.getMapper(UserMapper.class);

List<Integer> list = Arrays.asList(1);
QueryVo queryVo = new QueryVo();
queryVo.setUsers(list);
List<Integer> users = mapper.findUserByOrder_uid(queryVo);

System.out.println("user="+users);
session.close();
}


讲的东西有点杂,,,需要好好理一下才行,,最开始我是一脸懵的,,



关联查询

上来反手就是一个需求,嘿嘿

案例需求(一对一查询)

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

需要注意的是,因为一个订单信息只会是一个人下的订单,所以从查询订单信息出发关联查询用户信息为一对一查询。如果从用户信息出发查询用户下的订单信息则为一对多查询,因为一个用户可以下多个订单

订单表如下

package com.mybatis.pojo;

import java.util.Date;
import java.util.List;

public class Orders {
private Integer id;

private Integer userId;

private String number;

private Date createtime;

private String note;

private User user;//关联映射

public User getUser() {
return user;
}

public void setUser(User user) {
this.user = user;
}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public Integer getUserId() {
return userId;
}

public void setUserId(Integer userId) {
this.userId = userId;
}

public String getNumber() {
return number;
}

public void setNumber(String number) {
this.number = number == null ? null : number.trim();
}

public Date getCreatetime() {
return createtime;
}

public void setC
125de
reatetime(Date createtime) {
this.createtime = createtime;
}

public String getNote() {
return note;
}

public void setNote(String note) {
this.note = note == null ? null : note.trim();
}
}


这里提供俩种方案,

设置返回结果为po类

使用resultMap

方案一

创建一个po类

package cn.mybatis.pojo;

import java.io.Serializable;

//继承order 的属性
public class OrderCustom extends Order implements Serializable{

private String address;// 用户地址
private String username; //姓名

public void setAddress(String address) {
this.address = address;
}

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}
}


编写sql

<select id="findAllOrderAndUserInfo" resultType="cn.mybatis.pojo.OrderCustom">
select o.*,u.address,u.username from orders o,user u WHERE  o.user_id = u.id;
</select>


接口增加方法

public List<OrderCustom> findAllOrderAndUserInfo();


编写测试类

@Test
public void test_fun06(){
//获取session
SqlSession session = factory.openSession();
OrderMapper mapper = session.getMapper(OrderMapper.class);

List<Integer> list = Arrays.asList(1);
QueryVo queryVo = new QueryVo();
queryVo.setUsers(list);
List<OrderCustom> order = mapper.findAllOrderAndUserInfo();

System.out.println("order="+order);
session.close();
}


为了更好的展示运行结果,,我使用debug来截图



方案二

使用resultMap,定义专门的resultMap用于映射一对一查询结果。

创建一个resultMap 一对一关系

<resultMap id="findOrderAllUserMap" type="cn.mybatis.pojo.Order">
<!--数据库字段对应表字段-->
<id column="id" property="id"></id>
<result column="createtime"  property="createtime"></result>
<result column="number" property="number"></result>
<result column="user_id" property="userId"></result>
<result column="note" property="note"></result>

<!--添加关联关系,javaType="cn.mybatis.pojo.User"   user属性对应的类型-->
<association property="user" javaType="cn.mybatis.pojo.User">
<id column="userId" property="id"></id> <!--column  user表主键对应的列 propertites user具体的属性-->

<result column="username" property="username"></result>
<result column="address" property="address"></result>
</association>
</resultMap>

<select id="findAllOrderAndUserInfo" resultMap="findOrderAllUserMap">
select o.*,u.address,u.username from orders o,user u where o.user_id = u.id
</select>




那个,,,,看完我相信大家也是有点蒙的,,,,,花点时间理解把…

嗯,要不 我们再写一个案例加深印象??

案例需求(一对多查询)

查询所有用户信息,并且关联查询用户下的订单信息。

用户信息和订单信息为一对多关系。

同样有俩种解决方案,,,,,第一种使用po类的方法就不演示了

我们使用resultMap来做演示

因为用户是一的一方,所以在一的一方加上多的一方的对象集合,跟hibernate类似,

private List<Order> orders;
public void setOrders(List<Order> orders) {
this.orders = orders;
}


编写resultMap 以及 sql语句

//这里需要注意的是
user表中的主键是id, order表中的主键也是id,如果其中一个id,如果不用别名,,那么会出现数据混乱的情况,所以这里我们order查询出来的id 使用别名oid

<resultMap id="findUserAndOrderMap" type="cn.mybatis.pojo.User">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>

<!--一对一使用这个-->
<!--<association property=""-->

<!--一对多使用这个-->
<!--<collection property=""-->
<collection property="orders" ofType="cn.mybatis.pojo.Order">
<!--这里的oid 使用的是别名-->
<id column="oid" property="id"></id>

<!--column是列明,properties 是 pojo表中的属性名-->
<result column="number" property="number"></result>
<result column="createtime" property="createtime"></result>
<result column="note" property="note"></result>
</collection>
</resultMap>

<select id="findUserAndOrderInfo" resultMap="findUserAndOrderMap">
select u.* ,o.id oid,o.number,o.note,o.createtime from user u,orders o where u.id = o.user_id;
</select>


collection部分定义了用户关联的订单信息。表示关联查询结果集

property=”orders”:关联查询的结果集存储在User对象的上哪个属性。

ofType=”orders”:指定关联查询的结果集中的对象类型即List中的对象类型。此处可以使用别名,也可以使用全限定名。

接口添加方法

public List<User> findUserAndOrderInfo();


测试代码

@Test
public void test_fun07(){
//获取session
SqlSession session = factory.openSession();
UserMapper mapper = session.getMapper(UserMapper.class);

List<User> users = mapper.findUserAndOrderInfo();

System.out.println("user="+users);
session.close();
}


这里出现卡了很久,原因是 一对一 一对多的 类型 一个使用javaType ,一个是ofType ,这很坑

javaType 表示单个对象, ofType 表示List

myBatis 整合spring

1.创建一个工程

目录结构如下



2.导入jar包

1、spring的jar包

2、Mybatis的jar包

3、Spring+mybatis的整合包。

4、Mysql的数据库驱动jar包。

5、数据库连接池的jar包。

jar包自己收集,因为上传文件限制,这里就不能提供了,下面是我导入的所有jar包,是可以运行的,可以当做参考 ……. 注意了,需要特别导入spring + myBatis 的整合jar包



创建配置文件

db.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=itcast


log4j.properties

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n


applicationContext.xml

导入约束
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd"> 
<context:property-placeholder location="classpath:db.properties"/>

<!-- 配置 数据源  sqlsessionfacotry  -->
<bean id="dataSource" class="org.apache.commons.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" />
</bean>

<!-- sqlsessionfacotry -->
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory">
<property name="dataSource" ref="dataSource"></property>
<!-- mapperLocations指定 :xml的映射文件的位置 ,sql的xml文件的名字和接口的名字一致-->
<property name="mapperLocations" value="classpath:mapper/*Mapper.xml" />
</bean>

<context:component-scan base-package="com.mybatis.dao"></context:component-scan>

<!-- 作用:就是扫描指定的包里面的接口 生成代理对象 它的默认的bean的id 是类名首字母小写 。加载配置文件,要求接口和映射文件在同一个目录,而且名字一致-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.mybatis.dao" />
</bean>
</beans>


创建mapper 配置文件

<?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.mybatis.dao.UserMapper">
<select id="com.mybatis.dao.UserMapper" resultType="findAll">
select * from user
</select>
</mapper>


接口代码

import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface UserMapper {

public List<User> findAll();
}


测试代码

@Test
public void fun01(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");

UserMapper mapper = context.getBean(UserMapper.class);

List<User> all = mapper.findAll();

System.out.println("all"+all);
}


输出结果...因为网不好,,图片上传不上来,,就不上传图片了
all[User [id=1, username=王五, sex=2, birthday=null, address=null], User [id=10, username=张三, sex=1, birthday=Thu Jul 10 00:00:00 CST 2014, address=北京市], User [id=16, username=张小明, sex=1, birthday=null, address=河南郑州], User [id=22, username=陈小明, sex=1, birthday=null, address=河南郑州], User [id=24, username=张三丰, sex=1, birthday=null, address=河南郑州], User [id=25, username=陈小明, sex=1, birthday=null, address=河南郑州], User [id=26, username=王五, sex=null, birthday=null, address=null], User [id=28, username=李白, sex=男, birthday=Sat Jan 06 00:00:00 CST 2018, address=广东省], User [id=29, username=李白, sex=男, birthday=Sat Jan 06 00:00:00 CST 2018, address=广东省], User [id=30, username=李白, sex=男, birthday=Sat Jan 06 00:00:00 CST 2018, address=广东省]]


因为时间关系,后面内容可能没那么详细,,,,抱歉,,
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring mybatis 框架