Mybatis官方文档是学习Mybatis最好的入门资料:Mybatis 中文文档
参考文章链接:mybatis学习笔记 、 聊聊MyBatis缓存机制 、 MyBatis原理深入解析(一)
本文在上面引用中的几篇文章(mybatis学习笔记、聊聊MyBatis缓存机制、MyBatis原理深入解析(一))的基础上进行整理、合并,修改一部分内容,加入了部分自己的理解。
感谢原作者的付出。
文章很长,对 Mybatis 的最常用的基础部分做了总结和概括,基本不涉及源码和深入的实现原理。
本文总结jdbc编程的一般步骤,总结这样编程存在的问题,并附上典型地jdbc示例demo
1.数据库连接,使用时就创建,不使用立即释放,对数据库进行频繁连接开启和关闭,造成数据库资源浪费,影响数据库性能。
设想:使用数据库连接池管理数据库连接。
2.将sql语句硬编码到java代码中,如果sql语句修改,需要重新编译java代码,不利于系统维护。
设想:将sql语句配置在xml配置文件中,即使sql变化,不需要对java代码进行重新编译。
3.向preparedStatement中设置参数,对占位符号位置和设置参数值,硬编码在java代码中,不利于系统维护。
设想:将sql语句及占位符号和参数全部配置在xml中。
4.从resutSet中遍历结果集数据时,存在硬编码,将获取表的字段进行硬编码,不利于系统维护。
设想:将查询的结果集,自动映射成java对象。
package com.iot.mybatis.jdbc;
//import java.sql.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* Created by Administrator on 2016/2/21.
*/
public class JdbcTest {
public static void main(String[] args) {
//数据库连接
Connection connection = null;
//预编译的Statement,使用预编译的Statement提高数据库性能
PreparedStatement preparedStatement = null;
//结果集
ResultSet resultSet = null;
try {
//加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
//通过驱动管理类获取数据库链接
connection = DriverManager.getConnection("jdbc:mysql://120.25.162.238:3306/mybatis001?characterEncoding=utf-8", "root", "123");
//定义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();
}
}
}
}
}
JDBC 存在的问题以及相应的解决方案
数据库连接频繁的开启和关闭本身就造成了资源的浪费,影响系统的性能。
数据库连接的获取和关闭我们可以使用数据库连接池来解决资源浪费的问题。通过连接池就可以反复利用已经建立的连接去访问数据库了。减少连接的开启和关闭的时间。
但是现在连接池多种多样,可能存在变化,有可能采用DBCP的连接池,也有可能采用容器本身的JNDI数据库连接池
我们可以通过DataSource进行隔离解耦,我们统一从DataSource里面获取数据库连接,DataSource具体由DBCP实现还是由容器的JNDI实现都可以,所以我们将DataSource的具体实现通过让用户配置来应对变化
我们使用JDBC进行操作数据库时,SQL语句基本都散落在各个JAVA类中,这样有三个不足之处:
我们可以考虑不把SQL语句写到Java代码中,那么把SQL语句放到哪里呢?首先需要有一个统一存放的地方,我们可以将这些SQL语句统一集中放到配置文件或者数据库里面(以key-value的格式存放)。然后通过SQL语句的key值去获取对应的SQL语句。
既然我们将SQL语句都统一放在配置文件或者数据库中,那么这里就涉及一个SQL语句的加载问题。
很多情况下,我们都可以通过在SQL语句中设置占位符来达到使用传入参数的目的,这种方式本身就有一定局限性,它是按照一定顺序传入参数的,要与占位符一一匹配。但是,如果我们传入的参数是不确定的(比如列表查询,根据用户填写的查询条件不同,传入查询的参数也是不同的,有时是一个参数、有时可能是三个参数),那么我们就得在后台代码中自己根据请求的传入参数去拼凑相应的SQL语句,这样的话还是避免不了在Java代码里面写SQL语句的命运。既然我们已经把SQL语句统一存放在配置文件或者数据库中了,怎么做到能够根据前台传入参数的不同,动态生成对应的SQL语句呢?
- 我们先解决这个动态问题,按照我们正常的程序员思维是,通过if和else这类的判断来进行是最直观的,这个时候我们想到了JSTL中的 这样的标签,那么,能不能将这类的标签引入到SQL语句中呢?假设可以,那么我们这里就需要一个专门的SQL解析器来解析这样的SQL语句,但是,if判断的变量来自于哪里呢?传入的值本身是可变的,那么我们得为这个值定义一个不变的变量名称,而且这个变量名称必须和对应的值要有对应关系,可以通过这个变量名称找到对应的值,这个时候我们想到了key-value的Map。解析的时候根据变量名的具体值来判断。
- 假如前面可以判断没有问题,那么假如判断的结果是true,那么就需要输出的标签里面的SQL片段,但是怎么解决在标签里面使用变量名称的问题呢?这里我们需要使用一种有别于SQL的语法来嵌入变量(比如使用#变量名#)。这样,SQL语句经过解析后就可以动态的生成符合上下文的SQL语句。
- 怎么区分开占位符变量和非占位变量?有时候我们单单使用占位符是满足不了的,占位符只能为查询条件占位,SQL语句其他地方使用不了。这里我们可以使用#变量名#表示占位符变量,使用变量名表示非占位符变量。
执行SQL语句、获取执行结果、对执行结果进行转换处理、释放相关资源是一整套下来的。假如是执行查询语句,那么执行SQL语句后,返回的是一个ResultSet结果集,这个时候我们就需要将ResultSet对象的数据取出来,不然等到释放资源时就取不到这些结果信息了。我们从前面的优化来看,以及将获取连接、设置传入参数、执行SQL语句、释放资源这些都封装起来了,只剩下结果处理这块还没有进行封装,如果能封装起来,每个数据库操作都不用自己写那么一大堆Java代码,直接调用一个封装的方法就可以搞定了。
我们分析一下,一般对执行结果的有哪些处理,有可能将结果不做任何处理就直接返回,也有可能将结果转换成一个JavaBean对象返回、一个Map返回、一个List返回等`,结果处理可能是多种多样的。从这里看,我们必须告诉SQL处理器两点:第一,需要返回什么类型的对象;第二,需要返回的对象的数据结构怎么跟执行的结果映射,这样才能将具体的值copy到对应的数据结构上。
接下来,我们可以进而考虑对SQL执行结果的缓存来提升性能。缓存数据都是key-value的格式,那么这个key怎么来呢?怎么保证唯一呢?即使同一条SQL语句几次访问的过程中由于传入参数的不同,得到的执行SQL语句也是不同的。那么缓存起来的时候是多对。但是SQL语句和传入参数两部分合起来可以作为数据缓存的key值。
由于我们将所有SQL语句都放到配置文件中,这个时候会遇到一个SQL重复的问题,几个功能的SQL语句其实都差不多,有些可能是SELECT后面那段不同、有些可能是WHERE语句不同。有时候表结构改了,那么我们就需要改多个地方,不利于维护
当我们的代码程序出现重复代码时怎么办?将重复的代码抽离出来成为独立的一个类,然后在各个需要使用的地方进行引用。对于SQL重复的问题,我们也可以采用这种方式,通过将SQL片段模块化,将重复的SQL片段独立成一个SQL块,然后在各个SQL语句引用重复的SQL块,这样需要修改时只需要修改一处即可
本文对mybatis做一个简单介绍,包括框架原理,执行过程,开发方法,输入输出映射以及动态 sql 会在后续的系列文章中详细说明
mybatis是一个持久层的框架,是apache下的顶级项目。
mybatis让程序将主要精力放在sql上,通过mybatis提供的映射方式,自由灵活生成(半自动化,大部分需要程序员编写sql)满足需要sql语句。
mybatis可以将向 preparedStatement中的输入参数自动进行输入映射,将查询结果集灵活映射成java对象。(输出映射)
mybatis框架结构图:
1、配置mybatis的配置文件,SqlMapConfig.xml(名称不固定)
2、通过配置文件,加载mybatis运行环境,创建SqlSessionFactory会话工厂(SqlSessionFactory在实际使用时按单例方式)
3、通过SqlSessionFactory创建SqlSession。SqlSession是一个面向用户接口(提供操作数据库方法),实现对象是线程不安全的,建议sqlSession应用场合在方法体内。
4、调用sqlSession的方法去操作数据。如果需要提交事务,需要执行SqlSession的commit()方法。
5、释放资源,关闭SqlSession
1.原始dao 的方法
2.mapper代理开发方法(建议使用)
只需要程序员编写mapper接口(就是dao接口)。
程序员在编写mapper.xml(映射文件)和mapper.java需要遵循一个开发规范:
SqlMapConfig.xml配置文件:可以配置properties属性、别名、mapper加载。
是一个标准ORM框架(对象关系映射)。入门门槛较高的,不需要程序写sql,sql语句自动生成了。对sql语句进行优化、修改比较困难的。
应用场景:适用与需求变化不多的中小型项目,比如:后台管理系统,erp、orm、oa。。
专注是sql本身,需要程序员自己编写sql语句,sql修改、优化比较方便。mybatis是一个不完全的ORM框架,虽然程序员自己写sql,mybatis也可以实现映射(输入映射、输出映射)。
应用场景:适用与需求变化较多的项目,比如:互联网项目。
仅仅使用 Mybatis 进行简单的查询
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://120.25.162.238:3306/mybatis001?characterEncoding=utf-8" />
<property name="username" value="root" />
<property name="password" value="123" />
dataSource>
environment>
environments>
configuration>
<mapper namespace="test">
<select id="findUserById" parameterType="int" resultType="com.iot.mybatis.po.User">
SELECT * FROM user WHERE id=#{value}
select>
<select id="findUserByName" parameterType="java.lang.String" resultType="com.iot.mybatis.po.User">
SELECT * FROM user WHERE username LIKE '%${value}%'
select>
mapper>
在sqlMapConfig.xml中加载User.xml
<mappers>
<mapper resource="sqlmap/User.xml"/>
mappers>
程序代码
User.java
package com.iot.mybatis.po;
import java.util.Date;
/**
* Created by Administrator on 2016/2/21.
*/
public class User {
//属性名要和数据库表的字段对应
private int id;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址
// 省略 set/get 方法
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", sex=" + sex
+ ", birthday=" + birthday + ", address=" + address + "]";
}
}
package com.iot.mybatis.first;
import com.iot.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.List;
/**
* Created by Administrator on 2016/2/23.
*/
public class MybatisFirst {
//根据id查询用户信息,得到一条记录结果
@Test
public void findUserByIdTest() throws IOException{
// mybatis配置文件
String resource = "SqlMapConfig.xml";
// 得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建会话工厂,传入mybatis配置文件的信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 通过工厂得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 通过SqlSession操作数据库
// 第一个参数:映射文件中statement的id,等于=namespace+"."+statement的id
// 第二个参数:指定和映射文件中所匹配的parameterType类型的参数
// sqlSession.selectOne结果 是与映射文件中所匹配的resultType类型的对象
// selectOne查询出一条记录
User user = sqlSession.selectOne("test.findUserById", 1);
System.out.println(user);
// 释放资源
sqlSession.close();
}
// 根据用户名称模糊查询用户列表
@Test
public void findUserByNameTest() throws IOException {
// mybatis配置文件
String resource = "SqlMapConfig.xml";
// 得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建会话工厂,传入mybatis的配置文件信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(inputStream);
// 通过工厂得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// list中的user和映射文件中resultType所指定的类型一致
List<User> list = sqlSession.selectList("test.findUserByName", "小明");
System.out.println(list);
sqlSession.close();
}
}
输出:
findUserByIdTest()
...
DEBUG [main] - ==> Preparing: SELECT * FROM user WHERE id=?
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <== Total: 1
User [id=1, username=王五, sex=2, birthday=null, address=null]
...
findUserByNameTest()
...
DEBUG [main] - ==> Preparing: SELECT * FROM user WHERE username LIKE '%小明%'
DEBUG [main] - ==> Parameters:
DEBUG [main] - <== Total: 3
[User [id=16, username=张小明, sex=1, birthday=null, address=河南郑州], User [id=22, username=陈小明, sex=1, birthday=null, address=河南郑州], User [id=25, username=陈小明, sex=1, birthday=null, address=河南郑州]]
...
parameterType
在映射文件中通过parameterType指定输入参数的类型
resultType
在映射文件中通过resultType指定输出结果的类型
#{}
和${}
#{}
表示一个占位符号;
${}
表示一个拼接符号,会引起sql注入,所以不建议使用
selectOne
和selectList
selectOne
表示查询一条记录进行映射,使用selectList
也可以使用,只不过只有一个对象
selectList
表示查询出一个列表(参数记录)进行映射,不能够使用selectOne
查,不然会报下面的错:
org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3
添加、删除、更新用户
<insert id="insertUser" parameterType="com.iot.mybatis.po.User">
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
SELECT LAST_INSERT_ID()
selectKey>
INSERT INTO user (username,birthday,sex,address)values (#{username},#{birthday},#{sex},#{address})
insert>
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id=#{id}
delete>
<update id="updateUser" parameterType="com.iot.mybatis.po.User">
update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address}
where id=#{id}
update>
(注:这里的birthday
字段在mysql表中是DATE类型,在User类中birthday
属性是java的java.util.Date
类型,并没有进行转换就插入成功了。
看到有的文章说,在字段中有Date和DateTime类型,在插入数据时只要将实体的属性设置成Timestamp就会对应mysql的DateTime类型,Date会对应mysql的Date类型:
#{modified_date,jdbcType=TIMESTAMP}、#{date,jdbcType=DATE}
我上面的birthday
,配置成#{birthday,jdbcType=TIMESTAMP}
,结果也插入成功了,具体实现待查)
// 添加用户信息
@Test
public void insertUserTest() throws IOException {
// mybatis配置文件
String resource = "SqlMapConfig.xml";
// 得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建会话工厂,传入mybatis的配置文件信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(inputStream);
// 通过工厂得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 插入用户对象
User user = new User();
user.setUsername("王小军");
user.setBirthday(new Date());
user.setSex("1");
user.setAddress("河南郑州");
sqlSession.insert("test.insertUser", user);
// 提交事务
sqlSession.commit();
// 获取用户信息主键
System.out.println(user.getId());
// 关闭会话
sqlSession.close();
}
// 根据id删除 用户信息
@Test
public void deleteUserTest() throws IOException {
// mybatis配置文件
String resource = "SqlMapConfig.xml";
// 得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建会话工厂,传入mybatis的配置文件信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(inputStream);
// 通过工厂得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 传入id删除 用户
sqlSession.delete("test.deleteUser", 29);
// 提交事务
sqlSession.commit();
// 关闭会话
sqlSession.close();
}
// 更新用户信息
@Test
public void updateUserTest() throws IOException {
// mybatis配置文件
String resource = "SqlMapConfig.xml";
// 得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建会话工厂,传入mybatis的配置文件信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(inputStream);
// 通过工厂得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 更新用户信息
User user = new User();
//必须设置id
user.setId(27);
user.setUsername("王大军");
user.setBirthday(new Date());
user.setSex("2");
user.setAddress("河南郑州");
sqlSession.update("test.updateUser", user);
// 提交事务
sqlSession.commit();
// 关闭会话
sqlSession.close();
}
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
SELECT LAST_INSERT_ID()
selectKey>
如果没有在上面的配置中配置resultType
,则会报下面的异常
org.apache.ibatis.exceptions.PersistenceException:
### Error updating database. Cause: org.apache.ibatis.executor.ExecutorException: A query was run and no Result Maps were found for the Mapped Statement 'test.insertUser!selectKey'. It's likely that neither a Result Type nor a Result Map was specified.
### The error may exist in sqlmap/User.xml
### The error may involve test.insertUser!selectKey-Inline
### The error occurred while setting parameters
### SQL: SELECT LAST_INSERT_ID()
### Cause: org.apache.ibatis.executor.ExecutorException: A query was run and no Result Maps were found for the Mapped Statement 'test.insertUser!selectKey'. It's likely that neither a Result Type nor a Result Map was specified.
...
Caused by: org.apache.ibatis.executor.ExecutorException: A query was run and no Result Maps were found for the Mapped Statement 'test.insertUser!selectKey'. It's likely that neither a Result Type nor a Result Map was specified.
#{}
和${}
#{}
表示一个占位符号,#{}
接收输入参数,类型可以是简单类型,pojo、hashmap。
如果接收简单类型,#{}
中可以写成value或其它名称。
#{}
接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性…的方式获取对象属性值。
${}
表示一个拼接符号,会引用sql注入,所以不建议使用${}
。
${}
接收输入参数,类型可以是简单类型,pojo、hashmap。
如果接收简单类型,${}
中只能写成value。
${}
接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性…的方式获取对象属性值。
本文讲解SqlSession,并对两种方法( 原始dao开发和mapper代理开发 )分别做简单展示
SqlSessionFactoryBuilder
通过SqlSessionFactoryBuilder
创建会话工厂SqlSessionFactory
将SqlSessionFactoryBuilder
当成一个工具类使用即可,不需要使用单例管理SqlSessionFactoryBuilder
。在需要创建SqlSessionFactory
时候,只需要new一次SqlSessionFactoryBuilder
即可。
SqlSessionFactory
通过SqlSessionFactory
创建SqlSession
,使用单例模式管理sqlSessionFactory
(工厂一旦创建,使用一个实例)。将来mybatis和spring整合后,使用单例模式管理sqlSessionFactory
。
SqlSession
SqlSession
是一个面向用户(程序员)的接口。SqlSession中提供了很多操作数据库的方法:如:selectOne
(返回单个对象)、selectList
(返回单个或多个对象)。
SqlSession
是线程不安全的,在SqlSesion
实现类中除了有接口中的方法(操作数据库的方法)还有数据域属性。
SqlSession
最佳应用场合在方法体内,定义成局部变量使用。
程序员需要写dao接口和dao实现类
public interface UserDao {
//根据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;
}
package com.iot.mybatis.dao;
import com.iot.mybatis.po.User;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import java.util.List;
/**
* Created by Brian on 2016/2/24.
*/
public class UserDaoImpl implements UserDao{
// 需要向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 List<User> findUserByName(String name) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
List<User> list = sqlSession.selectList("test.findUserByName", name);
// 释放资源
sqlSession.close();
return list;
}
@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.delete("test.deleteUser", id);
// 提交事务
sqlSession.commit();
// 释放资源
sqlSession.close();
}
}
测试代码
package com.iot.mybatis.dao;
import java.io.InputStream;
import com.iot.mybatis.po.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
public class UserDaoImplTest {
private SqlSessionFactory sqlSessionFactory;
// 此方法是在执行testFindUserById之前执行
@Before
public void setUp() throws Exception {
// 创建sqlSessionFactory
// mybatis配置文件
String resource = "SqlMapConfig.xml";
// 得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建会话工厂,传入mybatis的配置文件信息
sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(inputStream);
}
@Test
public void testFindUserById() throws Exception {
// 创建UserDao的对象
UserDao userDao = new UserDaoImpl(sqlSessionFactory);
// 调用UserDao的方法
User user = userDao.findUserById(1);
System.out.println(user);
}
}
程序员需要编写
程序员编写mapper接口需要遵循一些开发规范,mybatis可以自动生成mapper接口实现类代理对象。
在mapper.xml中namespace等于mapper接口地址
namespace 命名空间,作用就是对sql进行分类化管理,理解为sql隔离
使用mapper代理方法开发,namespace有特殊重要的作用,namespace等于mapper接口地址
mapper.java接口中的方法名和mapper.xml中statement的id一致
mapper.java接口中的方法输入参数类型和mapper.xml中statement的parameterType指定的类型一致。
mapper.java接口中的方法返回值类型和mapper.xml中statement的resultType指定的类型一致。
<select id="findUserById" parameterType="int" resultType="com.iot.mybatis.po.User">
SELECT * FROM user WHERE id=#{value}
select>
//根据id查询用户信息
public User findUserById(int id) throws Exception;
总结:以上开发规范主要是对下边的代码进行统一生成:
User user = sqlSession.selectOne("test.findUserById", id);
sqlSession.insert("test.insertUser", user);
<mapper namespace="com.iot.mybatis.mapper.UserMapper">
<select id="findUserById" parameterType="int" resultType="com.iot.mybatis.po.User">
SELECT * FROM user WHERE id=#{value}
select>
<select id="findUserByName" parameterType="java.lang.String" resultType="com.iot.mybatis.po.User">
SELECT * FROM user WHERE username LIKE '%${value}%'
select>
<insert id="insertUser" parameterType="com.iot.mybatis.po.User">
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
SELECT LAST_INSERT_ID()
selectKey>
INSERT INTO user (username,birthday,sex,address)values (#{username},#{birthday},#{sex},#{address})
insert>
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id=#{id}
delete>
<update id="updateUser" parameterType="com.iot.mybatis.po.User">
update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address}
where id=#{id}
update>
mapper>
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
mappers>
public interface UserMapper {
//根据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;
//更新用户
public void updateUser(User user)throws Exception;
}
public class UserMapperTest {
private SqlSessionFactory sqlSessionFactory;
//注解Before是在执行本类所有测试方法之前先调用这个方法
@Before
public void setup() throws Exception{
//创建SqlSessionFactory
String resource="SqlMapConfig.xml";
//将配置文件加载成流
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建会话工厂,传入mybatis配置文件的信息
sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testFindUserById() throws Exception{
SqlSession sqlSession=sqlSessionFactory.openSession();
//创建UserMapper代理对象
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
//调用userMapper的方法
User user=userMapper.findUserById(1);
System.out.println(user.getUsername());
}
}
代理对象内部调用selectOne
或selectList
mapper接口方法参数只能有一个是否影响系统开发
mapper接口方法参数只能有一个,系统是否不利于扩展维护?系统框架中,dao层的代码是被业务层公用的。即使mapper接口只有一个参数,可以使用包装类型的pojo满足不同的业务方法的需求。
注意:持久层方法的参数可以包装类型、map…等,service方法中建议不要使用包装类型(不利于业务层的可扩展)。
本文主要讲解SqlMapConfig配置文件
参考mybatis – MyBatis 3
|
Configuration
SqlMapConfig.xml中配置的内容和顺序如下
(注:粗体是重点,斜体不常用)
将数据库连接参数单独配置在db.properties中,只需要在SqlMapConfig.xml中加载db.properties的属性值。在SqlMapConfig.xml中就不需要对数据库连接参数硬编码。
将数据库连接参数只配置在db.properties中。原因:方便对参数进行统一管理,其它xml可以引用该db.properties。
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://120.25.162.238:3306/mybatis001?characterEncoding=utf-8
jdbc.username=root
jdbc.password=123
在sqlMapConfig.xml加载属性文件:
<properties resource="db.properties">
properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
dataSource>
environment>
environments>
注意: MyBatis 将按照下面的顺序(优先级)来加载属性:
properties
元素体内定义的属性首先被读取。properties
元素中resource或url加载的属性,它会覆盖已读取的同名属性。parameterType
传递的属性,它会覆盖已读取的同名属性。建议:
properties
元素体内添加任何属性值,只将属性值定义在properties文件中。mybatis框架在运行时可以调整一些运行参数,比如:开启二级缓存、开启延迟加载…
全局参数将会影响mybatis的运行行为。具体参考官网:
mybatis-settings
在mapper.xml中,定义很多的statement,statement需要parameterType
指定输入参数的类型、需要resultType
指定输出结果的映射类型。
如果在指定类型时输入类型全路径,不方便进行开发,可以针对parameterType
或resultType
指定的类型定义一些别名,在mapper.xml中通过别名定义,方便开发。
参考 typeAliases
别名 | 映射的类型 |
---|---|
_byte | byte |
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
<typeAliases>
<package name="com.iot.mybatis.po"/>
typeAliases>
mybatis中通过typeHandlers完成jdbc类型和java类型的转换。例如:
<select id="findUserById" parameterType="int" resultType="user">
select * from user where id = #{id}
select>
mybatis自带的类型处理器基本上满足日常需求,不需要单独定义。
mybatis支持类型处理器
参考 typeHandlers
类型处理器 | Java类型 | JDBC类型 |
---|---|---|
BooleanTypeHandler | Boolean,boolean | 任何兼容的布尔值 |
ByteTypeHandler | Byte,byte | 任何兼容的数字或字节类型 |
ShortTypeHandler | Short,short | 任何兼容的数字或短整型 |
IntegerTypeHandler | Integer,int | 任何兼容的数字和整型 |
LongTypeHandler | Long,long | 任何兼容的数字或长整型(后面还有很多) |
<mapper resource="mapper/UserMapper.xml"/>
<mapper class="com.iot.mybatis.mapper.UserMapper"/>
目录示例
com.iot.mybatis.mapper------------------package包
|----UserMapper.java
|----UserMapper.xml
<package name="com.iot.mybatis.mapper"/>
将上边实现的动态sql判断代码块抽取出来,组成一个sql片段。其它的statement中就可以引用sql片段。
<sql id="query_user_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 LIKE '%${userCustom.username}%'
if>
if>
sql>
<select id="findUserList" parameterType="com.iot.mybatis.po.UserQueryVo"
resultType="com.iot.mybatis.po.UserCustom">
SELECT * FROM user
<where>
<include refid="query_user_where">include>
where>
select>
本文主要讲解mybatis的输入映射。
通过parameterType指定输入参数的类型,类型可以是
<select id="selectTeacher" parameterType="int" resultType="com.myapp.domain.Teacher">
select * from Teacher where c_id=#{id}
select>
因为 java 反射只能获取方法参数的类型,但无从得知方法参数的名字的,所以这里的”参数名“可以是任意的。
在基本类型中,我们只能传入一个参数。 如果要传入多个参数怎么办?比如要查询某个价格区间的商品,那么就需要构建minPrice、maxPrice两个参数,这时可以用到Map。 通过**#{map的KeyName}**即可获取传入的值。
<select id="searchByPrice" parameterType="Map" resultType="Product">
select * from Product where price >= #{minPrice} and price <= #{maxPrice}
select>
/**
Map 的定义
Map<String, Double> pricemap=new HashMap<String,Double>();
pricemap.put("minPrice", 1000.00);
pricemap.put("maxPrice", 6000.00);
*/
参数传递时,一定要保证sql语句中的#{minPrice}和map中的 key 值 一样,大小写敏感。否则会报参数错误。 Map 类型作为传入参数使用的并不多,主要有两个原因
正是因为这个原因,所以最好是用Java实体(POJO)作为传参。
class productVo {
Product pro;
public Product getProduct() {
return pro;
}
public void setProduct(Product product) {
this.pro = product;
}
}
在UserMapper.xml中定义用户信息综合查询(查询条件复杂,通过高级查询进行复杂关联查询)。
<select id="searchByPrice" parameterType="productVo" resultType="Product">
select * from Product where price >= #{pro.minPrice} and price <= #{pro.maxPrice}
select>
本文主要讲解mybatis的输出映射。
输出映射有两种方式
resultType
resultMap
MyBatis中在查询进行select映射的时候,返回类型可以用resultType,也可以用resultMap,**resultType是直接表示返回类型的,而resultMap则是对外部ResultMap的引用,但是resultType跟resultMap不能同时存在。**在MyBatis进行查询映射时,其实查询出来的每一个属性都是放在一个对应的Map里面的,其中键是属性名,值则是其对应的值。
resultType
进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。对于SQL语句查询出的字段在相应的pojo中必须有和它相同的字段对应,而resultType中的内容就是pojo在本项目中的位置。因此对于单表查询的话用resultType是最合适的。<typeAlias alias="Blog" type="com.tiantian.mybatis.model.Blog"/>
<select id="selectBlog" parameterType="int" resultType="Blog">
select * from t_blog where id = #{id}
select>
mybatis中使用resultMap完成高级输出结果映射。(一对多,多对多)
如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间作一个映射关系。
1.定义resultMap
2.使用resultMap作为statement的输出映射类型
<resultMap type="user" id="userResultMap">
<id column="id_" property="id"/>
<result column="username_" property="username"/>
resultMap>
<select id="findUserByIdResultMap" parameterType="int" resultMap="userResultMap">
SELECT id id_,username username_ FROM USER WHERE id=#{value}
select>
使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。
如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间作一个映射关系。
mybatis核心,对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接、组装。主要有以下四种:
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
if>
select>>
有时候在字符串作为判断条件的时候,同时要判断字符串是否为 null 和是否为空
有时我们不想应用到所有的条件语句,而只想从中择其一项。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
还是上面的例子,但是这次变为提供了“title”就按“title”查找,提供了“author”就按“author”查找的情形,若两者都没有提供,就返回所有符合条件的 BLOG
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<choose>
<when test="title != null">
AND title like #{title}
when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
when>
<otherwise>
AND featured = 1
otherwise>
choose>
select>
where 和 set 都是 trim 的一种具体做法。
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG
<where>
<if test="state != null">
state = #{state}
if>
<if test="title != null">
AND title like #{title}
if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
if>
where>
select>
<update id="updateAuthorIfNecessary">
update Author
<set>
<if test="username != null">username=#{username},if>
<if test="password != null">password=#{password},if>
<if test="email != null">email=#{email},if>
<if test="bio != null">bio=#{bio}if>
set>
where id=#{id}
update>
动态 SQL 的另外一个常用的操作需求是对一个集合进行遍历,通常是在构建 IN 条件语句的时候。向sql传递数组或List,mybatis使用foreach解析
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
foreach>
select>
<mapper namespace="com.dao.classMapper">
<select id="getClass" parameterType="int" resultMap="ClassResultMap">
select * from class c, teacher t where c.teacher_id=t.t_id and c.c_id=#{id}
select>
<resultMap type="me.gacl.domain.Classes" id="ClassResultMap">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher" javaType="me.gacl.domain.Teacher">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
association>
resultMap>
<select id="getClass2" parameterType="int" resultMap="ClassResultMap2">
select * from class where c_id=#{id}
select>
<resultMap type="me.gacl.domain.Classes" id="ClassResultMap2">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher" column="teacher_id" select="getTeacher"/>
resultMap>
<select id="getTeacher" parameterType="int" resultType="me.gacl.domain.Teacher">
SELECT t_id id, t_name name FROM teacher WHERE t_id=#{id}
select>
mapper>
mybatis使用resultMap的collection对关联查询的多条记录映射到一个list集合属性中。
<select id="getClass3" parameterType="int" resultMap="ClassResultMap3">
select * from class c, teacher t,student s where c.teacher_id=t.t_id and c.C_id=s.class_id and c.c_id=#{id}
select>
<resultMap type="me.gacl.domain.Classes" id="ClassResultMap3">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher" column="teacher_id" javaType="me.gacl.domain.Teacher">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
association>
<collection property="students" ofType="me.gacl.domain.Student">
<id property="id" column="s_id"/>
<result property="name" column="s_name"/>
collection>
resultMap>
<select id="getClass4" parameterType="int" resultMap="ClassResultMap4">
select * from class where c_id=#{id}
select>
<resultMap type="me.gacl.domain.Classes" id="ClassResultMap4">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher" column="teacher_id" javaType="me.gacl.domain.Teacher" select="getTeacher2">association>
<collection property="students" ofType="me.gacl.domain.Student" column="c_id" select="getStudent">collection>
resultMap>
<select id="getTeacher2" parameterType="int" resultType="me.gacl.domain.Teacher">
SELECT t_id id, t_name name FROM teacher WHERE t_id=#{id}
select>
<select id="getStudent" parameterType="int" resultType="me.gacl.domain.Student">
SELECT s_id id, s_name name FROM student WHERE class_id=#{id}
select>
另外,下面这篇文章对一对多的resultMap机制解释的很清楚:
MyBatis:一对多表关系详解(从案例中解析)
将查询用户购买的商品信息明细清单,(用户名、用户地址、购买商品名称、购买商品时间、购买商品数量)
针对上边的需求就使用resultType将查询到的记录映射到一个扩展的pojo中,很简单实现明细清单的功能。
<resultMap type="com.iot.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 property="ordersList" ofType="com.iot.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.iot.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.iot.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>
使用association和collection完成一对一和一对多高级映射(对结果有特殊的映射要求)。
association:
使用resultType无法将查询结果映射到pojo对象的pojo属性中,根据对结果集查询遍历的需要选择使用resultType还是resultMap。
collection:
resultMap可以实现高级映射(使用association
、collection
实现一对一及一对多映射),association
、collection
具备延迟加载功能。
延迟加载:先从单表查询、需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。
需求:
如果查询订单并且关联查询用户信息。如果先查询订单信息即可满足要求,当我们需要查询用户信息时再查询用户信息。把对用户信息的按需去查询就是延迟加载。
需要定义两个mapper的方法对应的statement。
1.只查询订单信息
SELECT * FROM orders
在查询订单的statement中使用association去延迟加载(执行)下边的satatement(关联查询用户信息)
<select id="findOrdersUserLazyLoading" resultMap="OrdersUserLazyLoadingResultMap">
SELECT * FROM orders
select>
2.关联查询用户信息
通过上边查询到的订单信息中user_id去关联查询用户信息,使用UserMapper.xml中的findUserById
<select id="findUserById" parameterType="int" resultType="com.iot.mybatis.po.User">
SELECT * FROM user WHERE id=#{value}
select>
上边先去执行findOrdersUserLazyLoading,当需要去查询用户的时候再去执行findUserById,通过resultMap的定义将延迟加载执行配置起来。
<resultMap type="com.iot.mybatis.po.Orders" id="OrdersUserLazyLoadingResultMap">
<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="user" javaType="com.iot.mybatis.po.User"
select="com.iot.mybatis.mapper.UserMapper.findUserById"
column="user_id">
association>
resultMap>
与非延迟加载的主要区别就在association
标签属性多了select
和column
<association property="user" javaType="com.iot.mybatis.po.User"
select="com.iot.mybatis.mapper.UserMapper.findUserById"
column="user_id">
//查询订单关联查询用户,用户信息是延迟加载
public List<Orders> findOrdersUserLazyLoading()throws Exception;
mybatis默认没有开启延迟加载,需要在SqlMapConfig.xml中setting配置。
在mybatis核心配置文件中配置:lazyLoadingEnabled、aggressiveLazyLoading
设置项 | 描述 | 允许值 | 默认值 |
---|---|---|---|
lazyLoadingEnabled | 全局性设置懒加载。如果设为‘false’,则所有相关联的都会被初始化加载 | true/false | false |
aggressiveLazyLoading | 当设置为‘true’的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载。 | true/false | true |
在SqlMapConfig.xml中配置:
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
settings>
不使用mybatis提供的association及collection中的延迟加载功能,如何实现延迟加载??
实现方法如下:
定义两个mapper方法:
实现思路:
先去查询第一个mapper方法,获取订单信息列表;在程序中(service),按需去调用第二个mapper方法去查询用户信息。
总之,使用延迟加载方法,先去查询简单的sql(最好单表,也可以关联查询),再去按需要加载关联查询的其它信息。
这部分一定要看这一篇文章: 聊聊MyBatis缓存机制
写的非常好。
本文主要将如何将spring和mybatis整合,只是作简单的示例,没有使用Maven构建。并展示mybatis与spring整合后如何进行原始dao开发和mapper代理开发。
SqlSessionFactory
。SqlSessionFactory
创建SqlSession
。(spring和mybatis整合自动完成)创建一个新的java工程(接近实际开发的工程结构)
jar包:
在applicationContext.xml配置sqlSessionFactory
和数据源
sqlSessionFactory
在mybatis和spring的整合包下。
<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" />
<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>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="mybatis/SqlMapConfig.xml" />
<property name="dataSource" ref="dataSource" />
bean>
beans>
<mapper namespace="test">
<select id="findUserById" parameterType="int" resultType="com.iot.ssm.po.User">
SELECT * FROM user WHERE id=#{value}
select>
mapper>
在SqlMapconfig.xml中加载User.xml
<mappers>
<mapper resource="sqlmap/User.xml"/>
mappers>
SqlSessionDaoSupport
)public interface UserDao {
//根据id查询用户信息
public User findUserById(int id) throws Exception;
}
dao接口实现类需要注入SqlSessoinFactory
,通过spring进行注入。这里spring声明配置方式,配置dao的bean
让UserDaoImpl实现类继承SqlSessionDaoSupport
public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao{
@Override
public User findUserById(int id) throws Exception {
//继承SqlSessionDaoSupport,通过this.getSqlSession()得到sqlSessoin
SqlSession sqlSession = this.getSqlSession();
User user = sqlSession.selectOne("test.findUserById",id);
return user;
}
}
在applicationContext.xml中配置dao
<bean id="userDao" class="com.iot.ssm.dao.UserDaoImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
bean>
public interface UserMapper {
//根据id查询用户信息
User findUserById(int id) throws Exception;
}
<mapper namespace="com.iot.ssm.mapper.UserMapper">
<select id="findUserById" parameterType="int" resultType="user">
SELECT * FROM user WHERE id=#{value}
select>
mapper>
MapperFactoryBean
创建代理对象
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
//mapperInterface指定mapper接口
<property name="mapperInterface" value="com.iot.ssm.mapper.UserMapper"/>
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
bean>
此方法问题:需要针对每个mapper进行配置,麻烦。
MapperScannerConfigurer
进行整个 mapper 包进行扫描(建议使用)
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.iot.ssm.mapper"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
bean>
mybaits需要程序员自己编写sql语句,mybatis官方提供逆向工程,可以针对单表自动生成mybatis执行所需要的代码(mapper.java,mapper.xml、po…)
企业实际开发中,常用的逆向工程方式:由数据库的表生成java代码。
先附上官网链接:
- MyBatis Generator
<generatorConfiguration>
<classPathEntry location="F:/cache/mysql-connector-java-5.1.28-bin.jar" />
<context id="DB2Tables" targetRuntime="MyBatis3">
<commentGenerator>
<property name="suppressDate" value="true"/>
<property name="suppressAllComments" value="true"/>
commentGenerator>
<jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost/test" userId="root" password="">
jdbcConnection>
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
javaTypeResolver>
<javaModelGenerator targetPackage="com.leige.domain" targetProject="src">
<property name="enableSubPackages" value="true"/>
<property name="trimStrings" value="true"/>
javaModelGenerator>
<sqlMapGenerator targetPackage="com.leige.domain" targetProject="src">
<property name="enableSubPackages" value="true"/>
sqlMapGenerator>
<javaClientGenerator type="XMLMAPPER" targetPackage="com.leige.dao" targetProject="src">
<property name="enableSubPackages" value="true"/>
javaClientGenerator>
<table tableName="student"
domainObjectName="Student"
>table>
<table tableName="teacher"
domainObjectName="Teacher"
>table>
context>
generatorConfiguration>
package com.leige.test;
import java.awt.geom.GeneralPath;
import java.awt.im.InputContext;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.log4j.chainsaw.Main;
import org.apache.log4j.lf5.util.Resource;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;
public class MybatisGen {
public static void generator() throws Exception{
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
//项目根路径不要有中文,我的有中文,所以使用绝对路径
File configFile = new File("F:/cache/generatorConfig.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
}
public static void main(String[] args) {
try {
generator();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}