赞
踩
数据表的sql下载 密码: xjjw
先来看一部分代码
Public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
//加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
//通过驱动管理类获取数据库链接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "mysql");
//定义sql语句 ?表示占位符
String sql = "select * from user where username = ?";
//获取预处理statement
preparedStatement = connection.prepareStatement(sql);
//设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
preparedStatement.setString(1, "王五");
//向数据库发出sql执行查询,查询出结果集
resultSet = preparedStatement.executeQuery();
//遍历查询结果集
while(resultSet.next()){
System.out.println(resultSet.getString("id")+" "+resultSet.getString("username"));
}
} catch (Exception e) {
e.printStackTrace();
}finally{
//释放资源
if(resultSet!=null){
try {
resultSet.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(preparedStatement!=null){
try {
preparedStatement.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

上面代码有如下几个问题:
Mybatis的运行环境(jar包)
从这里点击下载
笔者下载的是:
下载mybatis-3.4.6.zip解压即可
目录结构:
jar包结构
过程中需要数据库的连接,junit的调试,注意要将jar包build path!
log4j.properties
# Global logging configuration
# 开发环境下,日志级别要设置成DEBUG或者ERROR
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
SqlMapConfig.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>
<!-- 和spring整合后 environments配置将废除-->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事务管理-->
<transactionManager type="JDBC" />
<!-- 数据库连接池-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />
<property name="username" value="root" />
<property name="password" value="" />
</dataSource>
</environment>
</environments>
<!--加载映射文件-->
<mappers>
<mapper resource="sqlmap/User.xml"/>
</mappers>
</configuration>

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-->
<!--
findUserById
通过select执行数据库查询
id:标识映射文件的sql
将sql语句封装到mappedStatement对象中,所以将id称为Statement的id
#{}:表示一个占位符
parameterType:指定输入参数的类型
#{id}:其中的id表示接收输入的参数,参数的名称就是id,如果输入参数类型为简单类型,那么#{}中的参数可以任意,可以是value或其他
resultType:指定sql输出结果的所映射的Java对象类型,select指定的resultType表示将单条记录映射成的Java对象
-->
<select id="findUserById" parameterType="int" resultType="com.nuc.mybatis.po.User">
select * from user where id=#{VALUE }
</select>
<!--
findUserByName
${}:表示拼接字符串,将接收到的sql不加任何修饰拼接在sql语句里
使用${}拼接sql,可能会引起sql注入,一般不建议使用
${value}:接收参数的内容,如果传入的的是简单类型,${}中只能使用value
-->
<select id="findUserByName" parameterType="java.lang.String" resultType="com.nuc.mybatis.po.User">
select * from user WHERE username LIKE '%${value}%'
</select>
<!--
添加用户
parameterType:指定参数类型为pojo类型
#{}中指定pojo的属性名,接收到的pojo对象的属性值,mybatis通过OGNL获取对象的值
SELECT LAST_INSERT_ID():得到刚刚insert进去的记录的主键值,只适用于主键自增
非主键自的则需要使用uuid()来实现,表的id类型也得设置为tring(详见下面的注释)
keyProperty:将查询到的主键值设置到SparameterType指定的对象的哪个属性
order:SELECT LAST_INSERT_ID()执行顺序,相当于insert语句来说它的实现顺序
-->
<insert id="insertUser" parameterType="com.nuc.mybatis.po.User">
<!--uuid()-->
<!--
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.String">
SELECT uuid()
</selectKey>
insert into user (id,username,birthday,sex,address) value(#{id},#{username},#{birthday},#{sex},#{address})
-->
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
SELECT LAST_INSERT_ID()
</selectKey>
insert into user (username,birthday,sex,address) value(#{username},#{birthday},#{sex},#{address})
</insert>
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id=#{id}
</delete>
<update id="updateUser" parameterType="com.nuc.mybatis.po.User">
UPDATE user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}
</update>
</mapper>

User.java
package com.nuc.mybatis.po;
import java.util.Date;
public class User {
//用户po
//属性名和数据库字段名对应
private int id;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}

MybatisFirst.java
package com.nuc.mybatis.first;
import com.nuc.mybatis.po.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
public class MybatisFirst {
//根据id查询用户信息,得到一条记录
@Test
public void findUserByIdTest() throws IOException {
//mybatis配置文件
String resource = "SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建会话工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//通过SqlSession操作数据库
//第一个参数:映射文件中的statement的id,等于namespace+"."+statement的id
//第二个参数:指定和映射文件中所匹配的所有parameterType的类型
//sqlSession.selectOne()的结果是映射文件中所匹配的resultType类型的对象
User user = sqlSession.selectOne("test.findUserById",1);
System.out.println(user);
//释放资源
sqlSession.close();
}
//根据用户名称查询用户列表
@Test
public void findUserByName() throws IOException {
//mybatis配置文件
String resource = "SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建会话工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
List<User> list= sqlSession.selectList("test.findUserByName","小明");
System.out.println(list);
sqlSession.close();
}
/*
小结:
selectOne和selectList:
selectOne表示查询出一条记录进行映射。如果使用selectOne可以实现使用selectList也可以实现(list中只有一个对象)。
selectList表示查询出一个列表(多条记录)进行映射。如果使用selectList查询多条记录,不能使用selectOne。
如果使用selectOne报错:
org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 4
*/
@Test
public void insertUserTest() throws IOException {
//mybatis配置文件
String resource = "SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建会话工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = new User();
user.setUsername("宋江涛");
user.setBirthday(new Date());
user.setSex("男");
user.setAddress("山西");
//list中的user和映射文件User.xml中的resultType的类型一直
sqlSession.insert("test.insertUser",user);
//提交事务
sqlSession.commit();
//获取主键
System.out.println(user.getId());
sqlSession.close();
}
//删除用户
@Test
public void deleteUserTest() throws IOException {
//mybatis配置文件
String resource = "SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建会话工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//list中的user和映射文件User.xml中的resultType的类型一直
sqlSession.delete("test.deleteUser",30);
//提交事务
sqlSession.commit();
sqlSession.close();
}
//更新用户
@Test
public void updateUserTest() throws IOException {
//mybatis配置文件
String resource = "SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建会话工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = new User();
user.setId(27);
user.setUsername("宋江涛new2");
user.setBirthday(new Date());
user.setSex("男");
user.setAddress("山西太原new");
//list中的user和映射文件User.xml中的resultType的类型一直
sqlSession.update("test.updateUser",user);
//提交事务
sqlSession.commit();
sqlSession.close();
}
}

数据库的设计图
部分测试结果
jdbc的测试程序,前面已经沾过。
重点内容在代码的注释中均已说明
mybatis和hibernate本质区别和应用场景
hibernate:是一个标准ORM框架(对象关系映射)。入门门槛较高的,不需要程序写sql,sql语句自动生成了。
对sql语句进行优化、修改比较困难的。
mybatis:专注是sql本身,需要程序员自己编写sql语句,sql修改、优化比较方便。mybatis是一个不完全 的ORM框架,虽然程序员自己写sql,mybatis 也可以实现映射(输入映射、输出映射)。
企业进行技术选型,以低成本 高回报作为技术选型的原则,根据项目组的技术力量进行选择。
原始dao开发方法(程序需要编写dao接口和dao实现类)(掌握)
在test下创建com.nuc.mybatis.test,创建类UserDaoImplTest.java
具体目录结构:
结构中的相关mapper请先忽略
UserDao.java
package com.nuc.mybatis.dao;
import com.nuc.mybatis.po.User;
public interface UserDao {
//dao原始开发
//根据id查询用户信息
public User findUserById(int id) throws Exception;
//添加用户
public void insertUser(User user) throws Exception;
//删除用户
public void deleteUser(int id) throws Exception;
}
UserDaoImpl.java
package com.nuc.mybatis.dao;
import com.nuc.mybatis.po.User;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSession;
public class UserDaoImpl implements UserDao {
//原生态的dao
//需要向dao实现类里注入SqlSessionFactory
//通过构造方法
private SqlSessionFactory sqlSessionFactory;
public UserDaoImpl(SqlSessionFactory sqlSessionFactory){
this.sqlSessionFactory=sqlSessionFactory;
}
@Override
public User findUserById(int id) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = sqlSession.selectOne("test.findUserById",id);
sqlSession.close();
return user;
}
@Override
public void insertUser(User user) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.insert("test.insertUser",user);
sqlSession.commit();
sqlSession.close();
}
@Override
public void deleteUser(int id) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.insert("test.deleteUser",id);
sqlSession.commit();
sqlSession.close();
}
}

UserDaoImplTest.java
package com.nuc.mybatis.test;
import com.nuc.mybatis.mapper.UserMapper;
import com.nuc.mybatis.po.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import java.util.List;
public class UserMapperTest {
//原始dao的测试
private SqlSessionFactory sqlSessionFactory;
@Before
public void setUp() throws Exception{
String resource = "SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建会话工厂
sqlSessionFactory = new
SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testFindUserById() throws Exception{
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建UserMapper的对象,mybatis自动调用
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.findUserById(1);
System.out.println(user);
}
@Test
public void testFindUserByName() throws Exception{
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建UserMapper的对象,mybatis自动调用
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> list= userMapper.findUserByName("宋江涛");
System.out.println(list);
}
//其他的测试,可以照猫画虎
}

测试结果:
Mybatis的mapper接口(相当于dao接口)代理开发方法(掌握)
根据上面的结构图创建相应文件,源码如下:
UserMapper.java
package com.nuc.mybatis.mapper;
import com.nuc.mybatis.po.User;
import java.util.List;
public interface UserMapper {
//mapper代理开发和dao开发对比
// mapper接口,相当于dao接口,mybatis可以自动生成mapper接口实现类的代理对象
//根据id查询用户信息
public User findUserById(int id) throws Exception;
//根据用户名查询用户列表
public List<User>findUserByName(String name) throws Exception;
//添加用户
public void insertUser(User user) throws Exception;
//删除用户
public void deleteUser(int id) throws Exception;
}

UserMapper.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.nuc.mybatis.mapper.UserMapper">
<select id="findUserById" parameterType="int" resultType="com.nuc.mybatis.po.User">
select * from user where id=#{VALUE }
</select>
<select id="findUserByName" parameterType="java.lang.String" resultType="com.nuc.mybatis.po.User">
select * from user WHERE username LIKE '%${value}%'
</select>
<insert id="insertUser" parameterType="com.nuc.mybatis.po.User">
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
SELECT LAST_INSERT_ID()
</selectKey>
insert into user (username,birthday,sex,address) value(#{username},#{birthday},#{sex},#{address})
</insert>
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id=#{id}
</delete>
<update id="updateUser" parameterType="com.nuc.mybatis.po.User">
UPDATE user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}
</update>
</mapper>

在测试之前需要在SqlMapConfig.xml中加载mapper.xml这个映射文件
UserMapperTest.java
package com.nuc.mybatis.test;
import com.nuc.mybatis.mapper.UserMapper;
import com.nuc.mybatis.po.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import java.util.List;
public class UserMapperTest {
//原始mapper的测试
private SqlSessionFactory sqlSessionFactory;
@Before
public void setUp() throws Exception{
String resource = "SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建会话工厂
sqlSessionFactory = new
SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testFindUserById() throws Exception{
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建UserMapper的对象,mybatis自动调用
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.findUserById(1);
System.out.println(user);
}
@Test
public void testFindUserByName() throws Exception{
//返回列表测试
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建UserMapper的对象,mybatis自动调用
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> list= userMapper.findUserByName("宋江涛");
System.out.println(list);
}
}

部分测试结果:
总结:
mapper开发
mapper开发只需要遵守几个规范即可
其实,以上开发规范主要是对下边的代码进行统一生成:
User user = sqlSession.selectOne("test.findUserById", id);
sqlSession.insert("test.insertUser", user);
。。。。
mapper接口方法参数只能有一个是否影响系统 开发?mapper接口方法参数只能有一个,系统是否不利于扩展维护?
注意:持久层方法的参数可以包装类型、map。。。,service方法中建议不要使用包装类型(不利于业务层的可扩展)。
properties(属性)
特性: MyBatis 将按照下面的顺序来加载属性:
建议:
Mybatis输入映射(掌握)
目录结构
UserCustom.java
package com.nuc.mybatis.po;
public class UserCustom extends User {
//可扩展用户信息
}
UserQueryVo.java
package com.nuc.mybatis.po;
public class UserQueryVo {
//这里包装所需的查询条件
//用户查询条件
private UserCustom userCustom;
public UserCustom getUserCustom() {
return userCustom;
}
public void setUserCustom(UserCustom userCustom) {
this.userCustom = userCustom;
}
//可包装其他的查询条件,订单,商品。。。
}

UserMapper.xml中配置新的查询
UserMapperTest.java中新增测试
测试结果
Mybatis输出映射(掌握)
在上面的输入中,属于每一列都成功映射
当我们修改查询语句为:
其中id,起了别名叫做id_
测试结果:
很明显,由于查询条件,生日和地址为空,由于id的映射失败,导致查询id失败,只有sex一列映射成功,故查询成功(1代表男,2代表女)
如法炮制,对mapper.xml编辑和mapper.java编辑
测试代码(复制修改)
测试结果
总结:查询出来的结果集只有一行且一列,可以使用简单类型进行输出映射。
2.resultType的输出pojo对象和pojo列表
二、resultMap
<!--用户综合查询总数-->
<select id="findUserCount" parameterType="com.nuc.mybatis.po.UserQueryVo"
resultType="int">
select count(*) from user
<!--where可以自动去掉第一个and-->
<where>
<if test="userCustom!=null">
<if test="userCustom.sex!=null and userCustom.sex!=''">
and user.sex=#{userCustom.sex}
</if>
<if test="userCustom.username!=null and userCustom.username!=''">
and user.username=#{userCustom.username}
</if>
</if>
</where>
</select>

<!--sql片段
经验:基于单表来定义sql片段,这样,sql片段的可重用度就高
在sql片段中不要用where,因为你很有可能查询条件不止一个
-->
<sql id="Query_user">
<if test="userCustom!=null">
<if test="userCustom.sex!=null and userCustom.sex!=''">
and user.sex=#{userCustom.sex}
</if>
<if test="userCustom.username!=null and userCustom.username!=''">
and user.username=#{userCustom.username}
</if>
</if>
</sql>
<!--用户综合查询总数-->
<select id="findUserCount" parameterType="com.nuc.mybatis.po.UserQueryVo"
resultType="int">
select count(*) from user
<!--where可以自动去掉第一个and-->
<where>
<!--引用sql的id,如果refid引用的sql的id不在本mapper中,则需要家其他mapper的namespace-->
<include refid="Query_user"/>
</where>
</select>
<sql id="Query_user">
<if test="userCustom!=null">
<if test="userCustom.sex!=null and userCustom.sex!=''">
and user.sex=#{userCustom.sex}
</if>
<if test="userCustom.username!=null and userCustom.username!=''">
and user.username=#{userCustom.username}
</if>
</if>
<if test="ids!=null">
<!--
collection:指定输入对象集合中的属性
item:每次遍历生成的对象名
open:开始遍历拼接的串
close:结束时拼接的串
separator:每个对象的中间拼接的串
我们要实现 and(id=1 OR id=10 OR id=16)
-->
<foreach collection="ids" item="user_id" open="and(" close=")" separator="OR">
<!--每次遍历拼接的串-->
id=#{user_id}
</foreach>
</if>
</sql>

// 用户综合查询总数
@Test
public void testFindUser() throws Exception{
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建UserMapper的对象,mybatisCount自动调用
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//创建包对象,设置查询条件
UserQueryVo userQueryVo = new UserQueryVo();
UserCustom userCustom = new UserCustom();
// 由于这里使用动态sql所以不设置某个值,就不会拼接在sql语句中
// userCustom.setSex("1");
userCustom.setUsername("小明");
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(10);
list.add(16);
userQueryVo.setIds(list);
userQueryVo.setUserCustom(userCustom);
int count= userMapper.findUserCount(userQueryVo);
System.out.println(count);
}

数据模型分析思路
下来拿之前的数据库的表为例,具体字段不作说明
根据上面的步骤。
第一步:每张表记录的数据内容
第二步:每张表重要的字段设置
第三步:数据库级别表与表之间的关系
先分析数据库级别之间有关系的表之间的业务关系:
usre和orders:
orders和orderdetail:
第四步:表与表之间的业务关系
一对一
需求:查询订单信息,关联查询创建订单的用户信息
分析:
由于orders表中有一个外键(user_id),通过外键关联查询用户表只能查询出一条记录,可以使用内链接。
SELECT
orders.*,
USER.username,
USER.sex,
USER.address
FROM
orders,
USER
WHERE orders.user_id = user.id
Orders.java
package com.nuc.mybatis.po;
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;
//订单明细
private List<Orderdetail> orderdetails;
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 setCreatetime(Date createtime) {
this.createtime = createtime;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note == null ? null : note.trim();
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public List<Orderdetail> getOrderdetails() {
return orderdetails;
}
public void setOrderdetails(List<Orderdetail> orderdetails) {
this.orderdetails = orderdetails;
}
}

OrdersCustom .java
package com.nuc.mybatis.po;
public class OrdersCustom extends Orders {
private String username;
private String sex;
private String address;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}

OrdersMapperCustom.java
package com.nuc.mybatis.mapper;
import java.util.List;
public interface OrdersMapperCustom {
public List<OrdersMapperCustom> findOrdersUser()throws Exception;
}
OrdersMapperCustom .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.nuc.mybatis.mapper.OrdersMapperCustom">
<!--resultType:返回值的映射的pojo对象-->
<select id="findOrdersUser" resultType="com.nuc.mybatis.po.OrdersCustom">
SELECT
orders.*,
user.username,
user.sex,
user.address
FROM
orders,
user
WHERE orders.user_id = user.id
</select>
</mapper>

OrdersMapperTest.java
package com.nuc.mybatis.test;
import com.nuc.mybatis.mapper.OrdersMapperCustom;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import java.util.List;
public class OrdersMapperTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void setUp() throws Exception{
String resource = "SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建会话工厂
sqlSessionFactory = new
SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testFindOrdersUser() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 创建代理对象
OrdersMapperCustom ordersMapperCustom = sqlSession
.getMapper(OrdersMapperCustom.class);
// 调用maper的方法
List<OrdersMapperCustom> list = ordersMapperCustom.findOrdersUser();
System.out.println(list);
sqlSession.close();
}
}

测试结果
第三步:
<resultMap type="com.nuc.mybatis.po.Orders" id="OrdersUserResultMap">
<!-- 配置映射的订单信息 -->
<!-- id:指定查询列中的唯 一标识,订单信息的中的唯 一标识,如果有多个列组成唯一标识,配置多个id
column:订单信息的唯 一标识 列
property:订单信息的唯 一标识 列所映射到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"/>
<!-- 配置映射的关联的用户信息 -->
<!-- association:用于映射关联查询单个对象的信息
property:要将关联查询的用户信息映射到Orders中哪个属性
-->
<association property="user" javaType="com.nuc.mybatis.po.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>

<!-- 查询订单关联查询用户信息,使用resultmap -->
<select id="findOrdersUserResultMap" resultMap="OrdersUserResultMap">
SELECT
orders.*,
USER.username,
USER.sex,
USER.address
FROM
orders,
USER
WHERE orders.user_id = user.id
</select>
第四步
//查询订单关联查询用户使用resultMap
public List<Orders> findOrdersUserResultMap()throws Exception;
测试
@Test
public void testFindOrdersResultMap() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 创建代理对象
OrdersMapperCustom ordersMapperCustom = sqlSession
.getMapper(OrdersMapperCustom.class);
// 调用maper的方法
List<Orders> list = ordersMapperCustom.findOrdersUserResultMap();
System.out.println(list);
sqlSession.close();
}
总结
resultType:使用resultType实现较为简单,如果pojo中没有包括查询出来的列名,需要增加列名对应的属性,即可完成映射。如果没有查询结果的特殊要求建议使用resultType。
resultMap:需要单独定义resultMap,实现有点麻烦,如果对查询结果有特殊的要求,使用resultMap可以完成将关联查询映射pojo的属性中。resultMap可以实现延迟加载,resultType无法实现延迟加载。
一对多
添加属性在之前已经实现,且注释。
只需要配置xml文件和接口,写一个测试类即可
<!-- 订单及订单明细的resultMap
使用extends继承,不用在中配置订单信息和用户信息的映射
-->
<resultMap type="com.nuc.mybatis.po.Orders" id="OrdersAndOrderDetailResultMap" extends="OrdersUserResultMap">
<!-- 订单信息 -->
<!-- 用户信息 -->
<!-- 使用extends继承,不用在中配置订单信息和用户信息的映射 -->
<!-- 订单明细信息
一个订单关联查询出了多条明细,要使用collection进行映射
collection:对关联查询到多条记录映射到集合对象中
property:将关联查询到多条记录映射到com.nuc.mybatis.po.Orders哪个属性
ofType:指定映射到list集合属性中pojo的类型
-->
<collection property="orderdetails" ofType="com.nuc.mybatis.po.Orderdetail">
<!-- id:订单明细唯 一标识
property:要将订单明细的唯 一标识 映射到com.nuc.mybatis.po.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"/>
</collection>
</resultMap>
<!-- 查询订单关联查询用户及订单明细,使用resultmap -->
<select id="findOrdersAndOrderDetailResultMap" resultMap="OrdersAndOrderDetailResultMap">
SELECT
orders.*,
USER.username,
USER.sex,
USER.address,
orderdetail.id orderdetail_id,
orderdetail.items_id,
orderdetail.items_num,
orderdetail.orders_id
FROM
orders,
USER,
orderdetail
WHERE orders.user_id = user.id AND orderdetail.orders_id=orders.id
</select>

//查询订单(关联用户)及订单明细
public List<Orders> findOrdersAndOrderDetailResultMap() throws Exception;
@Test
public void testfindOrdersAndOrderDetailResultMap() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 创建代理对象
OrdersMapperCustom ordersMapperCustom = sqlSession
.getMapper(OrdersMapperCustom.class);
// 调用maper的方法
List<Orders> list = ordersMapperCustom.findOrdersAndOrderDetailResultMap();
System.out.println(list);
sqlSession.close();
}
总结:
多对多
映射思路
mapper.xml
<!-- 查询用户及购买的商品信息,使用resultmap -->
<select id="findUserAndItemsResultMap" resultMap="UserAndItemsResultMap">
SELECT
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
FROM
orders,
USER,
orderdetail,
items
WHERE orders.user_id = user.id AND orderdetail.orders_id=orders.id AND orderdetail.items_id = items.id
</select>

<!-- 查询用户及购买的商品 -->
<resultMap type="com.nuc.mybatis.po.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="ordersList" ofType="com.nuc.mybatis.po.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.nuc.mybatis.po.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.nuc.mybatis.po.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>

//查询用户购买商品信息
public List<User> findUserAndItemsResultMap()throws Exception;
测试
多对多查询总结
总结:使用resultMap是针对那些对查询结果映射有特殊要求的功能,比如特殊要求映射成list中包括 多个list
resultMap可以实现高级映射(使用association、collection实现一对一及一对多映射),association、collection具备延迟加载功能。
延迟加载:先从单表查询、需要时再从关联表去关联查询,大大提高 数据库性能,因为查询单表要比关联查询多张表速度要快。
不使用mybatis提供的association及collection中的延迟加载功能,如何实现延迟加载??
总之:使用延迟加载方法,先去查询简单的sql(最好单表,也可以关联查询),再去按需要加载关联查询的其它信息。
一级缓存
工作原理
测试:
//mybatis默认支持一级缓存,不需要在配置文件去配置。
@Test
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);
// 如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
//更新user1的信息
user1.setUsername("测试用户22");
userMapper.updateUser(user1);
//执行commit操作去清空缓存
sqlSession.commit();
//第二次发起请求,查询id为1的用户
User user2 = userMapper.findUserById(1);
System.out.println(user2);
sqlSession.close();
}

一级缓存应用
正式开发,是将mybatis和spring进行整合开发,事务控制在service中。
一个service方法中包括 很多mapper方法调用。
service{
//开始执行时,开启事务,创建SqlSession对象
//第一次调用mapper的方法findUserById(1)
//第二次调用mapper的方法findUserById(1),从一级缓存中取数据
//方法结束,sqlSession关闭
}
如果是执行两个service调用查询相同 的用户信息,不走一级缓存,因为session方法结束,sqlSession就关闭,一级缓存就清空。
二级缓存
// 二级缓存测试
@Test
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);
//这里执行关闭操作,将sqlsession中的数据写到二级缓存区域
sqlSession1.close();
//使用sqlSession3执行commit()操作
UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);
User user = userMapper3.findUserById(1);
user.setUsername("张明明");
userMapper3.updateUser(user);
//执行提交,清空UserMapper下边的二级缓存
sqlSession3.commit();
sqlSession3.close();
UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
// 第二次发起请求,查询id为1的用户
User user2 = userMapper2.findUserById(1);
System.out.println(user2);
sqlSession2.close();
}

useCache配置
<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">
总结:针对每次查询都需要最新的数据sql,要设置成useCache=false,禁用二级缓存。
刷新缓存(就是清空缓存)
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" flushCache="true">
总结:一般下执行完commit操作都需要刷新缓存,flushCache=true表示刷新缓存,这样可以避免数据库脏读。
mybatis整合ehcache
mybatis无法实现分布式缓存,需要和其它分布式缓存框架进行整合。
整合方法(掌握):
在config目录下加入ehcache的配置文件
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<defaultCache
maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>
二级缓存应用场景:
对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访问速度,业务场景比如:耗时较高的统计分析sql、电话账单查询sql等。
实现方法如下:通过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushInterval,比如设置为30分钟、60分钟、24小时等,根据需求而定。
二级缓存局限性
mybatis二级缓存对细粒度的数据级别的缓存实现不好,比如如下需求:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品信息,此时如果使用mybatis的二级缓存就无法实现当一个商品变化时只刷新该商品的缓存信息而不刷新其它商品的信息,因为mybaits的二级缓存区域以mapper为单位划分,当一个商品信息变化会将所有商品信息的缓存数据全部清空。解决此类问题需要在业务层根据需求对数据有针对性缓存。
mybatis的项目源码密码: b54x
mybatis的文档教程密码: pbvf
mybatis+springMVC的视频教程mybatis+springMVC
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。