Mybatis入门
一、简介
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。 MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
二、为什么要使用Mybatis
jdbc问题总结如下:
1、 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
2、 Sql语句在代码中硬编码,造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。
3、 使用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护。
4、 对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便。
三、Mybatis的架构
执行流程1、 mybatis配置SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。
mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。
2、 通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂
3、 由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
4、 mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
5、 Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
6、 Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。
7、 Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。
四、Mybatis与Hibernate的对比
1、Hibernate是完全的ORM框架。只需要对对象进行操作无需写sql语句。
Hibernate学习成本高。
开发速度很快
应用场景:传统项目的开发。管理系统的开发。
2、Mybatis并不是一个完全的orm框架。只能把返回值映射到一个对象中。只是对sql语句的一个封装。
学习成本很低,要求熟练掌握sql语句。
开发速度不是很快。
互联网项目:都是使用mysql的数据库集群。
五、Mybatis的搭建
下载地址:https://github.com/mybatis/mybatis-3/releases
jar包内容这里我使用maven来引入Mybatis的jar包
创建主配置文件(放在资源目录)
<?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:///test?characterEncoding=utf-8" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
</configuration>
改文件与Spring整合后将舍去
properties(属性)
settings(全局配置参数)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
environment(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源)
mappers(映射器)
创建pojo对象
package cn.zw.pojo;
import java.util.Date;
public class User {
private int id;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址
public User() {
super();
// TODO Auto-generated constructor stub
}
public User(int id, String username, String sex, Date birthday, String address) {
super();
this.id = id;
this.username = username;
this.sex = sex;
this.birthday = birthday;
this.address = 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;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", sex=" + sex + ", birthday=" + birthday + ", address="
+ address + "]";
}
}
创建mapper映射文件(放在资源目录下和pojo的同级目录)
<?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语句的隔离
id:同个命名空间下不可重复
#{}:站位符号,相当于jdbc中的?,如何使简单类型的参数名称任意,如果是pojo类型的{pojo的属性名称}
parameterType:参数类型
resultType:结果集封装到pojo类中
-->
<mapper namespace="user">
<select id="getUserById" parameterType="int" resultType="cn.zw.pojo.User">
select * from user where id = #{id}
</select>
</mapper>
在主配置文件中引入mapper映射文件
引入mapper映射文件测试查询单行
package cn.zw.hello;
import java.io.IOException;
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 cn.zw.pojo.User;
public class DemoTest {
@Test
public void fun01() throws IOException{
//通过SqlSessionFactoryBuilder获取SqlSessionFactory对象
SqlSessionFactoryBuilder sessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sessionFactoryBuilder.build(Resources.getResourceAsStream("SqlMapConfig.xml"));
//获取连接
SqlSession sqlSession = sqlSessionFactory.openSession();
//执行语句
User user = sqlSession.selectOne("user.getUserById", 1);
System.out.println(user);
sqlSession.close();
}
}
测试查询多行
<select id="selectByName" parameterType="String" resultType="cn.zw.pojo.User">
select * from user where username like #{username}
</select>
@Test
public void fun02() throws IOException{
//获取连接
SqlSession sqlSession = sqlSessionFactory.openSession();
List<User> users = sqlSession.selectList("user.selectByName", "%xiao%");
System.out.println(users);
sqlSession.close();
}
插入一条数据
<insert id="save" parameterType="cn.zw.pojo.User" >
INSERT INTO `user` (
`user`.username,
`user`.sex,
`user`.birthday,
`user`.address
)
VALUES
(#{userName},#{sex},#{birthday},#{address})
</insert>
@Test
public void fun03() throws IOException{
User user = new User();
user.setUsername("铁甲小宝");
user.setSex("男");
user.setBirthday(new Date());
user.setAddress("大阪");
//获取连接
SqlSession sqlSession = sqlSessionFactory.openSession();
int insert = sqlSession.insert("user.save", user);
sqlSession.commit();
}
插入一条数据并返回主键
<insert id="save2" parameterType="cn.zw.pojo.User" >
<selectKey order="AFTER" keyProperty="id" resultType="int">
SELECT LAST_INSERT_ID();
</selectKey>
INSERT INTO `user` (
`user`.username,
`user`.sex,
`user`.birthday,
`user`.address
)
VALUES
(#{username},#{sex},#{birthday},#{address})
</insert>
删除一条记录
<delete id="delete" parameterType="int">
DELETE FROM `user` WHERE id = #{id};
</delete>
@Test
public void fun05() throws IOException{
//获取连接
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.delete("user.delete", 2);
sqlSession.commit();
}
更新一条数据
<update id="update" parameterType="cn.zw.pojo.User">
update user set username = #{username} WHERE id = #{id}
</update>
@Test
public void fun06() throws IOException {
User user = new User();
user.setId(3);
user.setUsername("蟑螂恶霸");
user.setSex("男");
user.setBirthday(new Date());
user.setAddress("大阪");
// 获取连接
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.update("user.update",user);
sqlSession.commit();
}
六、开发中使用dao模式
传统方式:接口+实现类+mapper映射文件(xml)
传统然后实现类再去映射文件中调用sql语句
mapper代理方式(官方推荐):接口+映射文件
代理相比传统的方式来说,省去了一步实现接口的步骤,所以会方便开发者,下面我们就来看看用这种方式需要满足什么条件?
开发规范:
1)mapepr映射文件的namespace应该是接口的全路径。
2)接口的方法名称应该和sql语句的id一致。
3)接口的参数类型应该和parameterType一致。
4)接口返回值类型应该和ResultType保持一致。
package cn.zw.mapper;
import cn.zw.pojo.User;
public interface UserMapper {
void save(User user);
void delete(int id);
void update(User user);
User findOne(int id);
}
<?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="cn.zw.mapper.UserMapper">
<insert id="save" parameterType="cn.zw.pojo.User">
INSERT INTO
`user` (
`user`.username,
`user`.sex,
`user`.birthday,
`user`.address
)
VALUES
(#{username},#{sex},#{birthday},#{address})
</insert>
<delete id="delete" parameterType="int">
DELETE FROM `user` WHERE id =
#{id};
</delete>
<update id="update" parameterType="cn.zw.pojo.User">
update user set username =
#{username} WHERE id = #{id}
</update>
<select id="findOne" parameterType="int" resultType="cn.zw.pojo.User">
select *
from user where id = #{id}
</select>
</mapper>
规范
public class DemoTest2 {
SqlSessionFactory sqlSessionFactory = null;
@Before
public void init() throws IOException {
// 通过SqlSessionFactoryBuilder获取SqlSessionFactory对象
SqlSessionFactoryBuilder sessionFactoryBuilder = new SqlSessionFactoryBuilder();
sqlSessionFactory = sessionFactoryBuilder.build(Resources.getResourceAsStream("SqlMapConfig.xml"));
}
@Test
public void fun01() throws IOException {
SqlSession session = sqlSessionFactory.openSession();
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.findOne(3);
System.out.println(user);
}
}
网友评论