什么是MyBatis?
MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除 了几乎所有的 JDBC 代码和参数的手工设置以及结果集的检索。MyBatis 使用简单的 XML 或注解用于配置和原始映射,将接口和 Java 的 POJOs(Plain Ordinary Java Objects,普通的 Java 对象)映射成数据库中的记录。
MyBatis的前身是iBatis,MyBatis在iBatis的基础上面,对代码结构进行了大量的重构和简化;
员工的增删改查
1.环境准备
1.1 本文使用的是 MyBatis3.1.1 版本,下载 mybatis-3.1.1-bundle.zip
1.2 解压文件,将lib
目录的包,核心包mybatis-3.1.1.jar
,mysql驱动包mysql-connector-java-5.1.21.jar
导入到项目中.
1.3 在项目的资源目录resources
中新建 mybatis.cfg.xml
名字可以随意取,没有特殊的要求.
1.4 在 mybatis.cfg.xml
文件中添加数据源和事务管理器的配置信息,配置如下:
注意需要把mybatis-3-config.dtd
约束关联到项目中
<?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="em">
<environment id="em">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybatis"/>
<property name="username" value="root"/>
<property name="password" value="admin"/>
</dataSource>
</environment>
</environments>
</configuration>
<environments default="em">
:
表示myBatis中的数据源环境,可以配置多个数据源,default=”em”表示应用下面N多个数据源中的哪个数据源.
<environment id="em">
:
表示数据源相关的信息,id是该数据源的编号.
<transactionManager type="JDBC"/>
:
表示使用JDBC的事务管理器,是org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory的别名,这个配置写成
<transactionManager type="org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory"/>
也是可以的.
<dataSource type="POOLED">
:
配置数据源,POOLED的权限定名为:org.apache.ibatis.datasource.pooled.PooledDataSourceFactory
,这句话也可以写成:
<dataSource type="org.apache.ibatis.datasource.pooled.PooledDataSourceFactory">
<property name="driver" value="com.mysql.jdbc.Driver"/>
:
配置数据库驱动.
<property name="url" value="jdbc:mysql:///mybatis"/>
配置数据库连接信息.
<property name="username" value="root"/>
配置数据库账号. 需要改成你自己的账号
<property name="password" value="admin"/>
配置数据库密码.需要改成你自己的密码
2.保存对象
2.1 创建实体类User.java(@Setting需要用到lombok.jar包 Lombok介绍,自己提供Setter/Getter方法也可以.)
package com._520it.mybatis.domain;
import java.io.Serializable;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Setter@Getter@ToString
public class User implements Serializable {
private Long id;
private String username;
private String password;
private Integer age;
}
2.2 在对应的数据库中创建user表
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`username` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`age` int(3) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8;
2.3 在domain目录下,新建实体的映射文件,建议起名为UserMapper.xml(注意关联dtd约束)
<?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._520it.mybatis.domain.UserMapper">
<insert id="save"
parameterType="com._520it.mybatis.domain.User"
useGeneratedKeys="true"
keyColumn="id"
keyProperty="id">
insert into user(username,password,age)
values
(#{username},#{password},#{age})
</insert>
</mapper>
在这个配置文件中只要保证namespace+id是唯一的即可,目前建议namespace名字就写成com._520it.mybatis.domain.UserMapper
(后面程序用得上),
标签<insert>
:表示插入语句的标签.
属性id
:在命名空间中唯一的标识符,可以被用来引用这条语句。.
属性parameterType
:将会传入这条语句的参数类型的完全限定名或别名,参数可选.
属性useGeneratedKeys
:( 仅 对 insert 有 用 ) 这 会 告 诉 MyBatis 使 用 JDBC 的 getGeneratedKeys 方法来取出由数据(比如:像 MySQL的auto_increament 和 SQL Server 的identity)内部生成的主键,默认值:false。
属性keyColumn
:(仅对 insert 有用) 标记一个属性, MyBatis 会通过 getGeneratedKeys 或者通过 insert 语句的 selectKey 子元素设置它的值。 默认: 不设置。
属性keyProperty
:(仅对 insert 有用) 标记一个属性, MyBatis 会通过 getGeneratedKeys 或者通过 insert 语句的 selectKey 子元素设置它的值。 默认: 不设置。
#{属性名}
:默认情况下,如果参数使用#{}格式,mybatis会在创建的PreparedStatement中为这个参数添加一个占位符(?)。这样做能保证SQL安全性,是推荐的做法。 但有时你只是想直接在 SQL语句中插入一个不改变的字符串。比如,像 ORDER BY,只是希望从参数中得到一个排序的列名,并拼凑到SQL中,你可以这样来使用:
ORDER BY ${columnName}
2.4 将实体的映射文件配置到总配置文件中.
<?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="em">
<!--此处省略,和上面一样的-->
</environments>
<!-- 关联实体的映射文件 -->
<mappers>
<!--resource:找的是映射文件的路径 -->
<mapper resource="com/_520it/mybatis/domain/UserMapper.xml"/>
</mappers>
</configuration>
2.5 编写测试代码,将对象保存入库.
package com._520it.mybatis.domain;
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;
public class CRUDTest {
@Test
public void testSave() throws Exception{
//1.创建SessionFactory对象
//Resources.getResourceAsStream("mybatis.cfg.xml")
//去classpath目录中寻找指定名字文件,读取成stream
SqlSessionFactory sf = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis.cfg.xml"));
//2.创建session对象
SqlSession session = sf.openSession();
//3.创建需要保存的对象
User u = new User();
u.setUsername("admin");
u.setPassword("666");
u.setAge(18);
//4.调用api中的方法吧对象保存入库
//statement表示需要执行的SQL对应的位置namespace+id
session.insert("com._520it.mybatis.domain.UserMapper.save", u);
//5.提交事务
session.commit();
//6.释放资源
session.close();
System.out.println(u);
}
}
2.6 如果能将数据保存入库说明配置和代码是没有问题的.
3.对象更新
3.1在UserMapper.xml中的mapper节点中添加如下的配置:
<update id="update" parameterType="com._520it.mybatis.domain.User">
update user
set
username=#{username},
password=#{password},
age=#{age}
where id = #{id}
</update>
3.2测试代码如下:
@Test
public void testUpdate() throws Exception {
SqlSessionFactory sf = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis.cfg.xml"));
SqlSession session = sf.openSession();
User u = new User();
u.setId(1L);
u.setUsername("jack");
u.setPassword("888");
u.setAge(20);
session.update("com._520it.mybatis.domain.UserMapper.update", u);
session.commit();
session.close();
}
4.查询单个对象
4.1 在UserMapper.xml中的mapper节点中添加查询的标签:
<select id="get"
parameterType="java.lang.Long"
resultType="com._520it.mybatis.domain.User">
select * from user where id = #{id}
</select>
属性resultType
:查询出来的结果集中每一条记录封装成什么类型对象.这个类型可以是权限定名或者别名.
(此时结果集中只有一条数据.)
注意:凡是查询的标签必须加上resultType
或resultMap
否则会报错.resultMap
后面会讲到.
#{属性名}
:去传入的对象中通过内省找对应属性名的get方法,如果在对象中找不到方法,此时就应用当前传入对象的值.所以该查询语句写成如下也是可行的.
select * from user where id = #{xxoo}
select * from user where id = #{我就写中文怎么着}
因为在下面方法在调用的时候传入的是Long类型的值,此时#{ooxx}
在Long类型中找不到对应的getOoxx()方法,所以#{ooxx}
就应用传入的Long类型对象的值.
4.2编写测试方法完成查询:
@Test
public void testGet() throws Exception {
SqlSessionFactory sf = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis.cfg.xml"));
SqlSession session = sf.openSession();
User u = session.selectOne("com._520it.mybatis.domain.UserMapper.get", 1L);
System.out.println(u);
session.close();
}
注意:selectOne方法查询结果集中只能返回一条记录,如果查询的结果超过一条记录,会抛出异常.请看源码中selectOne方法.
public <T> T selectOne(String statement, Object parameter) {
// Popular vote was to return null on 0 results and throw exception on too many.
List<T> list = this.<T>selectList(statement, parameter);
if (list.size() == 1) {
return list.get(0);
} else if (list.size() > 1) {
throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
} else {
return null;
}
}
5.查询一组对象
5.1在UserMapper.xml中的mapper节点中添加查询的标签:
<select id="selectAll" resultType="com._520it.mybatis.domain.User" >
select * from user
</select>
注意:resultType
写的是,有同学会觉得这块不是需要返回一个集合吗?不应该返回的类型是List的类型吗?
请仔细阅读resultType的作用:
查询出来的结果集中每一条记录封装成什么类型对象.这个类型可以是权限定名或者别名.
而且通过查看selectOne的源码,我们不难发现,selectOne的底层其实是调用selectList的方法,所以查询单个对象和查询一组对象是一样的.所以标签中的resultType也是一样的.
5.2 编写测试方法完成查询:
@Test
public void testList() throws Exception {
SqlSessionFactory sf = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis.cfg.xml"));
SqlSession session = sf.openSession();
List<User> users = session.selectList("com._520it.mybatis.domain.UserMapper.selectAll");
for(User u:users){
System.out.println(u);
}
session.close();
}
6.对象的删除
6.1 在UserMapper.xml中的mapper节点中添加删除的标签:
<delete id="delete" parameterType="java.lang.Long">
delete from user where id = #{id}
</delete>
6.2编写测试代码进行删除:
@Test
public void testDelete() throws Exception {
SqlSessionFactory sf = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis.cfg.xml"));
SqlSession session = sf.openSession();
session.delete("com._520it.mybatis.domain.UserMapper.delete",1L);
session.commit();
session.close();
}
7.监控MyBatis的运行
7.1 如果需要实现类似Hibernate中show_sql的功能,将执行的sql语句打印出来.需要添加日志相关的配置,在resources目录中添加log4j.properties日志配置文件.配置如下:
# Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.com._520it.mybatis.domain=TRACE
# 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
第四行中的log4j.logger.[UserMapper.xml文件中的namespace] = TRACE
.需要一致才能打印SQL出来,如果没有日志打印,请检查是否写对了,可以配成:
log4j.logger.com=TRACE
表示mapper.xml中namespace中包含com的都会监控SQL的执行.
8.MyBatis的运行流程和Hibernate的对比
和hibernate对比,MyBatis更基础,要求使用者自己控制的东西更多。mybatis完成了基本的一些ORM概念,但是没有Hibernate那么完善。要使用mybatis,程序员的关注点更集中于SQL和数据库结构设计。mybatis没有hibernate使用起来那么面向对象,所以,在使用mybatis的时候,hibernate的一些思想和设计需要改变。
MyBatis的好处:更底层,对性能控制更有优势。