Mybatis运用mapper代码实现和Spring的整合(一)
实现Mybatis利用Mapper代理实现与Spring,利用容器管理SqlSession。
引言
先前做的java项目中一直使用的EclipseLink和Hibernate,两种ORM框架,现在用Mybatis实现,当然它们之间各有各的优点,同样也有缺点,有时候,一个项目中是可以存在两种框架一起使用的,在项目中,技术选型很重要。Mybatis是一个持久层的框架,是apache下的顶级项目,mybatis让程序将主要的精力放在sql上,通过mybatis提供的映射方式,自由灵活生成。
Mybatis的主要是靠sql语句来进行实现对数据库持久化的,这就是mybatis的硬伤,当然,它也因为是靠sql语句进行实现,很灵活但不好维护。
画了一张简单的思维导图,咱们按照图进行说明:
mybatis的框架:
我们现在说一个Mybatis的框架,当然能用图说明,我们尽量不要使用文字:
对于图的说明:数据库链接的初期,只要使用时就会创建,不适用立刻释放,对数据库进行很频繁链接开启和关闭,造成数据库资源浪费,影响了数据库的性能。因此我们需要使用数据库连接池进行管理数据库的连接。这里我们需要使用sqlSessionFactory会话工厂进行管理。另外我们将sql语句硬编码到java代码中,如果sql语句修改,需要重新编译java代码,不利于系统维护,这里我们使用了将sql语句配置在xml配置文件中,即使sql变化,不需要对java代码进行编译了。另外,我们向proparedStatement中设置参数,对战位富豪位置和设置参数,也要放到xml文件中。从另外我们总是从resultSet中便利结果集数据,不利于系统维护,因此,我们将查询的结果集,自动映射成java对象。
简单的流程:
由于篇幅有限,我们直接在Spring整合工程中提到。
与spring的整合:
这里我们使用的是Mapper代理的形式,将我们所有的Mybatis的mapper代理放在SqlSessionFactory中进行管理,另外,将SqlSessionFactory嫁给Spring容器管理。具体:通过SqlSessionFactoryBuilder创建会话工厂SqlSessionFactory,将SqlSessionFactoryBuilder当成一个工具类使用即可,不需要使用单例管理SqlSessionFactoryBuilder。在需要创建SqlSessionFactory时候,只需要new一次SqlSessionFactoryBuilder即可。通过SqlSessionFactory创建sqlSession,通过单利模式管理SqlSessionFactory,交给Spring来进行管理。
我们整合的思路是,需要spring通过单例方式管理SqlSessionFactory,spring和mybatis整合生成代理对象,使用SQLSessionFactory创建SqlSession。(spring和mybatis整合自动完成)持久层的mapper需要由spring进行管理。
整合代码:
1、jar包
2、创建配置文件
首先看我们的目录结构:
mybatis下面的配置SqlMapConfig.xml
<span style="font-size:18px;"><?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>
<!-- 别名定义 -->
<typeAliases>
<!-- 批量别名定义 指定包名,mybatis自动扫描包中的po类,自动定义别名,别名就是类名(首字母大写或小写都可以) -->
<package name="com.tgb.ncre.po" />
</typeAliases>
<!-- 加载 映射文件 -->
<mappers>
<!--1、 可以一个一个的添加 -->
<!--<mapper resource="sqlmap/User.xml" /> -->
<!--2、建议使用, 批量加载mapper 指定mapper接口的包名,mybatis自动扫描包下边所有mapper接口进行加载 遵循一些规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在一个目录
中 上边规范的前提是:使用的是mapper代理方法 和spring整合后,使用mapper扫描器,这里不需要配置了 -->
<package name="com.tgb.ncre.mapper"/>
</mappers>
</configuration></span>
db.properties文件:
<span style="font-size:18px;">jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=root</span>
添加log4j.properties文件:
<span style="font-size:18px;"># Global logging configuration
#\u5728\u5f00\u53d1\u73af\u5883\u4e0b\u65e5\u5fd7\u7ea7\u522b\u8981\u8bbe\u7f6e\u6210DEBUG\uff0c\u751f\u4ea7\u73af\u5883\u8bbe\u7f6e\u6210info\u6216error
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</span>
sqlmap文件夹下我们暂时不用。是用dao直接注入SqlSessionFactory的时候,才用到的,我们这里用到的是在mapper中直接添加xml文件的。
下面是最重要的spring的applicationContext.xml文件,我们在这个文件下进行注入SqlSession的。
<span style="font-size:18px;"><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="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>
<!-- sqlSessinFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 加载mybatis的配置文件 -->
<property name="configLocation" value="mybatis/SqlMapConfig.xml" />
<!-- 数据源 -->
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 原始dao接口 -->
<bean id="userDao" class="com.tgb.ncre.dao.UserDaoImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
<!-- mapper配置
MapperFactoryBean:根据mapper接口生成代理对象
-->
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<!--mapperInterface指定mapper接口 -->
<property name="mapperInterface" value="com.tgb.ncre.mapper.UserMapper"/>
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
<!-- mapper批量扫描,从mapper包中扫描出mapper接口,自动创建代理对象并且在spring容器中注册
遵循规范:将mapper.java和mapper.xml映射文件名称保持一致,且在一个目录 中
自动扫描出来的mapper的bean的id为mapper类名(首字母小写)
-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 指定扫描的包名
如果扫描多个包,每个包中间使用半角逗号分隔 -->
<property name="basePackage" value="com.tgb.ncre.mapper"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
</beans></span>
配置文件就建好了,是这样的:
我们现在创建src文件中,我们的pojo的java兑现个,和mapper代理。
我们先看src的文件目录:
User类:
<span style="font-size:18px;">package cn.itcast.ssm.po;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
public class User implements Serializable {
//属性名和数据库表的字段对应
private int id;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址
//用户创建的订单列表
private List<Orders> ordersList;
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;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", sex=" + sex
+ ", birthday=" + birthday + ", address=" + address + "]";
}
public List<Orders> getOrdersList() {
return ordersList;
}
public void setOrdersList(List<Orders> ordersList) {
this.ordersList = ordersList;
}
}
</span>
order类:
<span style="font-size:18px;">package com.tgb.ncre.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;
}
}</span>
Orderdetail类:
<span style="font-size:18px;">package com.tgb.ncre.po;
public class Orderdetail {
private Integer id;
private Integer ordersId;
private Integer itemsId;
private Integer itemsNum;
//明细对应的商品信�?
private Items items;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getOrdersId() {
return ordersId;
}
public void setOrdersId(Integer ordersId) {
this.ordersId = ordersId;
}
public Integer getItemsId() {
return itemsId;
}
public void setItemsId(Integer itemsId) {
this.itemsId = itemsId;
}
public Integer getItemsNum() {
return itemsNum;
}
public void setItemsNum(Integer itemsNum) {
this.itemsNum = itemsNum;
}
public Items getItems() {
return items;
}
public void setItems(Items items) {
this.items = items;
}
@Override
public String toString() {
return "Orderdetail [id=" + id + ", ordersId=" + ordersId
+ ", itemsId=" + itemsId + ", itemsNum=" + itemsNum + "]";
}
}</span>
Items类:
<span style="font-size:18px;">package com.tgb.ncre.po;
import java.util.Date;
public class Items {
private Integer id;
private String name;
private Float price;
private String pic;
private Date createtime;
private String detail;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name == null ? null : name.trim();
}
public Float getPrice() {
return price;
}
public void setPrice(Float price) {
this.price = price;
}
public String getPic() {
return pic;
}
public void setPic(String pic) {
this.pic = pic == null ? null : pic.trim();
}
public Date getCreatetime() {
return createtime;
}
public void setCreatetime(Date createtime) {
this.createtime = createtime;
}
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail == null ? null : detail.trim();
}
}</span>
然后,我们看com.tgb.ncre.mapper:
Usermapper.java
<span style="font-size:18px;">package com.tgb.ncre.mapper;
import static org.junit.Assert.*;
import com.tgb.ncre.po.User;
public interface UserMapper {
//根据id查询用户信息
public User findUserById(int id) throws Exception;
}
</span>
UserMapper.xml:
<span style="font-size:18px;"><?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">
<!-- namespace命名空间,作用就是对sql进行分类化管理,理解sql隔离
注意:使用mapper代理方法开发,namespace有特殊重要的作用,namespace等于mapper接口地址
-->
<mapper namespace="com.tgb.ncre.mapper.UserMapper">
<select id="findUserById" parameterType="int" resultType="user">
SELECT * FROM USER WHERE id=#{value}
</select>
</mapper>
</span>
注意:大家一定要这里的两个mapper包中的java类和xml的名称一定要相同才行,否则,在applicationContext.xml中创建SqlSession的时候,扫描不到所有的文件。
好了,现在我们就进行test:
右击我们的UserMapper.java,选择“New”——“Others”:
之后,我们写代码:
<span style="font-size:18px;">package com.tgb.ncre.mapper;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.tgb.ncre.po.User;
public class UserMapperTest {
private ApplicationContext applicationContext;
@Before
public void setUp() throws Exception {
applicationContext = new ClassPathXmlApplicationContext("classpath:spring/applicationContext.xml");
}
@Test
public void testFindUserById() throws Exception {
UserMapper userMapper = (UserMapper) applicationContext.getBean("userMapper");
User user = userMapper.findUserById(1);
System.out.println(user);
}
}
</span>
Ok了,运行,JunitTest:
总结:
我们在研究持久层的框架的时候,要从多方面考虑,当我们学习Mybatis的时候,就要想有没有其他的ORM框架,拿出来进行比较。这样,我们才能很好地做技术选型,另外,之后,我们在学习Mybatis的时候,还要想到,如何才能一步一步优化。
更多推荐
所有评论(0)