MyBatis 本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。
MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装。MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。
1 第一个MyBatis程序
首先需要加入需要的jar包,构建Spring环境请参考:Spring学习之第一个hello world程序。这里我们需要加入mybatis包和MysqL驱动包,使用IDEA环境来开发程序,最后工程加入的包如下图所示:
然后需要在test数据库中新建测试表user,sql语句如下所示:
create table users ( id int primary key auto_increment,name varchar(20),age int ); insert into users (name,age) values('Tom',12); Jack11);
1.1 定义表对应的实体类
public class User { private id; private String name; age; public User() { } public User(int id,String name, age) { this.id = id; this.name = name; this.age = age; } getId() { return id; } void setId( id) { String getName() { name; } void setName(String name) { getAge() { void setAge( age; } @Override String toString() { return "User{" + "id=" + id + ",name='" + name + '\'' + ",age=" + age + '}'; } }
1.2 定义MyBatista的mybatisConfig.xml配置文件和user表的sql映射文件userMapper.xml
mybatisConfig.xml文件,该文件是在src目录下新建的。
<?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="development"> <!-- development:开发环境 work:工作模式 --> environment id> transactionManager type="JDBC" /> 数据库连接方式 --> dataSource ="POOLED"> property name="driver" value="com.MysqL.jdbc.Driver" /> ="url"="jdbc:MysqL://192.168.1.150/test" ="username"="root" ="password"="123456" </dataSourceenvironmentenvironments 注册表映射文件 --> mappersmapper resource="com/mybatis/userMapper.xml"/> >
userMapper.xml文件,该配置文件在com.mybatis包下,user表对应的实体类User也在com.mybatis包下。
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="com.mybatis.userMapper" 根据id查询一个User对象 select ="getUser" parameterType="int" resultType="com.mybatis.User"> select * from users where id=#{id} select="getUserAll" select * from users > 插入一个User对象 insert ="insertUser" insert into users (name,age) value(#{name},#{age}) insert 删除一个User对象 delete ="deleteUser"="int" delete from users where id=#{id} delete 更新一个User对象update ="updateUser" update users set name=#{name},age=#{age} where id=#{id} updatemapper>
测试代码如下:
mybaitstest { sqlSessionFactory sessionFactory = null; sqlSession sqlSession = ; { String resource = "mybatisConfig.xml"; // 加载mybatis的配置文件(它也加载关联的映射文件) Reader reader = try { reader = Resources.getResourceAsReader(resource); } catch (IOException e) { e.printStackTrace(); } 构建sqlSession的工厂 sessionFactory = new sqlSessionFactoryBuilder().build(reader); 创建能执行映射文件中sql的sqlSession,默认是手动提交事务的,使用自动提交的话加上参数 true sqlSession = sessionFactory.openSession(true); } testSelectUser() { 映射sql的标识字符串 String statement = "com.mybatis.userMapper" + ".getUser" 执行查询返回一个唯一user对象的sql User user = sqlSession.selectOne(statement,1); System.out.println(user); } testSelectAll() { List<User> users = sqlSession.selectList("com.mybatis.userMapper.getUserAll"); System.out.println(users); } testInsertUser(User user) { int insert = sqlSession.insert("com.mybatis.userMapper.insertUser",user); 如果不是自动提交的话,需要使用 sqlSession。commit() System.out.println(insert); } void testDeleteUser(int delete = sqlSession.delete("com.mybatis.userMapper.deleteUser" testUpdateUser(User user) { int update = sqlSession.update("com.mybatis.userMapper.updateUser"static void main(String[] args) throws IOException { mybaitstest().testSelectUser(); } }
最后输出结果为:
2 基于注解的方式使用MyBatis
基于注解的方式使用MyBatis,首先定义对应表的sql映射接口。
interface IUserMapper { @Insert("insert into users (name,#{age})") add(User user); @Delete("delete from users where id=#{id}"int deleteById( id); @Update("update users set name=#{name},age=#{age} where id=#{id}" update(User user); @Select("select * from users where id=#{id}"public User getById( id); @Select("select * from users"public List<User> getAll(); }
然后在mybatisConfig.xml配置文件中注册该接口:
测试示例:
/** * 使用注解测试的方法 */ test() { IUserMapper userMapper = sqlSession.getMapper(IUserMapper.); User user = userMapper.getById(1); System.out.println(user); }
3 如何简化配置操作
以上两个程序示例都是直接在配置文件中写连接数据库的信息,其实还可以专门把数据库连接信息写到一个db.proteries文件中,然后由配置文件来读取该db.properies文件信息。db.proteries文件内容如下:
然后在mybatisConfig.xml配置文件中将数据库环境信息更改为如下所示:
properties ="db.properties"/> ="${driverClass}" ="${jdbcUrl}" ="${user}" ="${password}" >
配置表对应的sql映射文件时,可以使用别名来简化配置,在mybatisConfig.xml中添加如下配置,在userMapper中parameterType就可以配置为"_User"。
typeAliasestypeAlias ="com.mybatis.User" alias="_User">
4 字段名与实体类属性名不匹配的冲突
orders ( order_id floatinto orders (order_no,order_price) aaabbb13ccc14);
创建对应表的类:
Order { i; String no; price; Order() { } public Order(int i,String no,1)"> price) { this.i = i; this.no = no; this.price = price; } getI() { i; } void setI( i) { String getNo() { no; } setNo(String no) { getPrice() { void setPrice( price; } }
mybaitsConfig.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> <properties resource="db.properties"/> <typeAliases> <typeAlias type="com.mybatis.Order" alias="Order"/> </typeAliases> <environments default="development"> <!-- development:开发环境 work:工作模式 --> <environment id="development"> <transactionManager type="JDBC" /> <!-- 数据库连接方式 --> <dataSource type="POOLED"> <property name="driver" value="${driverClass}" /> <property name="url" value="${jdbcUrl}" /> <property name="username" value="${user}" /> <property name="password" value="${password}" /> </dataSource> </environment> </environments> <!-- 注册表映射文件 --> <mappers> <mapper resource="com/mybatis/orderMapper.xml"/> </mappers> </configuration>
接下来配置orderMapper.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.mybatis.orderMapper"> <!-- 根据id查询一个Order对象 --> <select id="getOrder" parameterType="int" resultType="Order"> SELECT order_id id,order_no no,order_price price FROM orders WHERE order_id=#{id} </select> <!-- 这种解决字段与属性冲突方式较常用 --> <select id="getOrder2" parameterType="int" resultType="Order" resultMap="getOrder2Map"> SELECT * FROM orders WHERE order_id=#{id} </select> <!-- resultMap 封装映射关系 id 专门针对主键 result 针对一般字段 --> <resultMap id="getOrder2Map" type="Order"> <id property="id" column="order_id"/> <result property="no" column="order_price"/> <result property="price" column="order_price"/> </resultMap> </mapper>
测试用例:
MyBaitsMain { sqlSessionFactory sessionFactory = main(String[] args) { String statement = "com.mybatis.orderMapper.getOrder"; String statement2 = "com.mybatis.orderMapper.getOrder2"; Order order = new MyBaitsMain().sqlSession.selectOne(statement,2); System.out.println(order); order = new MyBaitsMain().sqlSession.selectOne(statement2,1)">); System.out.println(order); } }
输出结果为:
5 实现关联表查询
5.1 一对一关联
这里实现班级id查询班级信息,班级信息中包括老师信息。首先创建表结构:
CREATE TABLE teacher( t_id INT PRIMARY KEY AUTO_INCREMENT,t_name VARCHAR() ); class( c_id INTALTER TABLE class ADD CONSTRAINT fk_teacher_id FOREIGN KEY (teacher_id) REFERENCES teacher(t_id); INSERT INTO teacher(t_name) VALUES(LS1'LS2); INTO class(c_name,teacher_id) bj_a1bj_b2);
定义表对应的实体类:
Teacher { String name; Teacher() { } public Teacher( id,String name) { name; } @Override return "Teacher{" + "id=" + id + ",name='" + name + '\'' + '}'; } }
Classes { Teacher teacher; Classes() { } public Classes(this.teacher = teacher; } Teacher getTeacher() { setTeacher(Teacher teacher) { return "Classes{" + "id=" + id + ",teacher=" + teacher + '}'; } }
定义sql映射文件,需要在mybatisConfig.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.mybatis.classesMapper"> <!-- 根据班级id查询班级信息(包括老师信息) --> <select id="getClasses" parameterType="int" resultMap="ClassesMap"> SELECT * FROM class c,teacher t WHERE c.teacher_id = t.t_id and c.c_id = #{id} </select> <!-- 联表查询 --> <resultMap id="ClassesMap" type="com.mybatis.Classes"> <id property="id" column="c_id"/> <result property="name" column="c_name"/> <association property="teacher" column="teacher_id" javaType="com.mybatis.Teacher"> <id property="id" column="t_id"/> <result property="name" column="t_name"/> </association> </resultMap> <!-- 嵌套查询 --> <select id="getClasses2" parameterType="int" resultMap="ClassesMap2">class WHERE c_id=#{id} </select> <select id="getTeacher" parameterType="int" resultType="com.mybatis.Teacher"> SELECT t_id id,t_name FROM teacher WHERE t_id=#{id} </select> <resultMap id="ClassesMap2" type="com.mybatis.Classes"> <id property="id" column="c_id"/> <result property="name" column="c_name"/> <association property="teacher" column="teacher_id" select="getTeacher"> </association> </resultMap> </mapper>
测试类:
main(String[] args) { String statement = "com.mybatis.classesMapper.getClasses"; String statement2 = "com.mybatis.classesMapper.getClasses2"; Classes classes = ); System.out.println(classes); classes = ); System.out.println(classes); } }
输出结果:
5.2 一对多关联
这里实现班级id查询班级信息,班级信息中包括老师信息和学生信息。首先创建表结构:
student( s_id INTO student(s_name,class_id) xs_Axs_Bxs_Cxs_D2xs_Exs_F2);
定义表对应的实体类:
class Student { private id; private String name; public Student(= id; this.name Student() { } getId() { public void setId( id) { this.id void setName(String name) { this.name @Override return "Student{" + "id=" + id ",name=" + name + '\'' + }; } }
定义sql映射文件,需要在mybatisConfig.xml中注册该表映射文件。
="com.mybatis.classesMapper2"="getClasses" resultMap="ClassesMap" SELECT * FROM class c,student s,teacher t WHERE c.c_id=s.class_id AND c.c_id=#{id} resultMap ="ClassesMap" type="com.mybatis.Classes"id property="id" column="c_id"result ="name"="c_name"association ="teacher" javaType="com.mybatis.Teacher"="t_id"="t_name"association collection: 做一对多关联查询的 ofType: 指定集合中元素对象的类型 collection ="students" ofType="com.mybatis.Student"="s_id"="s_name"collectionresultMap 第二种方式 ="getClasses2"="ClassesMap2" SELECT * FROM class WHERE c_id=#{id} ="getTeacher"="getStudent" SELECT s_id id,s_name name FROM student WHERE class_id=#{id} ="ClassesMap2"="teacher_id" select="getTeacher"="c_id"="getStudent">
测试类:
main(String[] args) { String statement = "com.mybatis.classesMapper2.getClasses"; String statement2 = "com.mybatis.classesMapper2.getClasses2"); System.out.println(classes); } }
输出结果:
6 MyBatis的缓存
正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持
- 一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空。
- 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。
- 对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。
7 Spring集成MyBatis
Spring集成MyBatis,开发环境为IDEA,打开IDEA,新建工程,工程名为spring-mybatis。注意,这里我选择的是带有Web功能的工程,其实在Spring集成MyBatis示例中并没有用到Web功能,这个可选可不选。
1、添加工程所需的jar包,比如MysqL驱动包、Spring包、commons-logging包等,最后添加的包结构图如下:
最后整个工程文件如下所示:
2、然后需要在test数据库中新建测试表user,sql语句如下所示:
create table users ( id primary key auto_increment,name varchar(20 ); insert into users (name,age) values('Tom',12); insert into users (name,age) values('Jack',11);
3、定义表对应的实体类和表操作接口。
package com.luoxn28.test; User() { } public User(String name,1)">; } }
import java.util.List; UserDao { insert(User user); update(User user); int delete( id); getAll(); }
4、定义表映射配置文件userDao.xml和MyBatis配置文件mybatisConfig.xml。
="com.luoxn28.test.UserDao"="insert"="com.luoxn28.test.User" INSERT users (name,age) VALUES (#{name},1)">="update" UPDATE users set name=#{name},1)">="delete" DELETE FROM users where id=#{id} ="getById" SELECT * FROM users WHERE id=#{id} ="getAll" SELECT * FROM users >
="com/luoxn28/test/userMapper.xml"/> >
5、配置Spring的applicationContext.xml文件
beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd" 0.导入外部配置文件 context:property-placeholder location="classpath:db.properties"/> 1.配置数据源 DriverManagerDataSource bean ="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"="${user}"="${password}"="driverClassName"="${driverClass}"="${jdbcUrl}"bean 2.mybatis的sqlSession工厂 sqlSessionfactorybean ="sqlSessionFactory"="org.mybatis.spring.sqlSessionfactorybean" ref="dataSource"="typeAliasesPackage"="com.luoxn28.test"/> 实体类包名,自动将实体类的简单类名映射成为别名 ="configLocation"="classpath:mybatisConfig.xml" 3.mybatis自动扫描加载sql映射文件 MapperScannerConfigurer <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.luoxn28.test"/> <property name="sqlSessionFactory" ref="sqlSessionFactory"/> </bean> --> 4.事务管理 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> 5.声明式事务 transaction-manager引用定义的事务管理器 <tx:annotation-driven transaction-manager="transactionManager"/> ="userDao"="org.mybatis.spring.mapper.Mapperfactorybean"="mapperInterface"="sqlSessionFactory"beans>
6、编写测试类SMTest
org.springframework.context.ApplicationContext; org.springframework.context.support.ClassPathXmlApplicationContext; org.testng.annotations.BeforeTest; org.testng.annotations.Test; SMTest { private ApplicationContext context = ; private UserDao userDao = ; @BeforeTest init() { context = new ClassPathXmlApplicationContext("applicationContext.xml"); userDao = (UserDao) context.getBean("userDao"); } @Test testInsert() { System.out.println(userDao.insert(new User("luoxn28",23))); } @Test testUpdate() { System.out.println(userDao.update(new User(10,"luoxn28",22 testDelete() { System.out.println(userDao.delete(10)); } @Test testGetById() { System.out.println(userDao.getById(10 getGetAll() { System.out.println(userDao.getAll()); } }
参考资料:
1、尚硅谷-MyBatis学习视频