MyBatis不介绍,知道是一个持久化的框架即可!要熟悉Sql语句和Java
官方文档地址:
直接上HelloWorld!
MyBatis Helloworld
首先,创建数据库吧,其实开发中也是,先设计一下表的字段。这里我们先创建一个数据表,就一个用户表:sob_user
1)我们创建数据库my_batis,然后用数据库软件连接一下!
测试连接–>成功!
接下来我们就可以创建表了!我们这个用户表字段有:id,username,email,password
CREATE TABLE sob_user(`id` INTEGER PRIMARY KEY AUTO_INCREMENT,
`username` VARCHAR(255) NOT NULL ,
`passowrd` VARCHAR(255) NOT NULL ,
`email` VARCHAR(255) NOT NULL );
执行结果:
sql> CREATE TABLE sob_user(`id` INTEGER PRIMARY KEY AUTO_INCREMENT,
`username` VARCHAR(255) NOT NULL ,
`passowrd` VARCHAR(255) NOT NULL ,
`email` VARCHAR(255) NOT NULL )
[2018-07-08 16:04:50] completed in 46ms
然后我们插入一条记录吧:
测试一下查询
好啦,数据库有了,表有了,记录有了!
接下来就开始MyBatis的Hello world吧!
下载相关的jar包,也可以用Maven来构建
这是MyBatis在github上的地址:
https://github.com/mybatis/mybatis-3
发布地址:
https://github.com/mybatis/mybatis-3/releases
我这里下载了一个 mybatis-3.4.6.zip的版本
接着我们引入jar包,添加依赖,我们还需要一个mysql的驱动
如下图:
有了jar包,我们就要去看看文档怎么用了,在我们下载的zip文件里头有说明文档的:
jar包我们有了,从文档里说,我们要配置一个xml文件,这个文件怎么配置的呢?在文档的下面就有说到了!
我们创建一个配置文件,放到conf目录下即可,这个配置文件名字我们叫:mybatis-config.xml
这是文档里的内容:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
大概的结构是这样子的:
这个配置文件我们需要修改一下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 名称空间 -->
<mapper namespace="org.mybatis.example.SobUserMapper">
<!-- id是唯一标识,后面的是返回类型,假设我们要返回我们的SobUser对象,那么就把这个bean类扔进去 -->
<select id="selectSobUser" resultType="com.sunofbeaches.domain.SobUser">
<!-- sql语句,后面这个是参数 也就是从传递过来的参数中拿到username,根据这个来chaxun-->
select * from sob_user where username = #{username}
</select>
</mapper>
有了这个配置文件了,前面我们看了文档,通过这个配置文件可以创建一个SqlSessionFactory
Building SqlSessionFactory from XML
怎么创建呢?文档里也有说:
我们也等下再说,我们还需要用到一个Mapper.xml,也就是一个映射配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 名称空间 -->
<mapper namespace="org.mybatis.example.BlogMapper">
<!-- id是唯一标识,后面的是返回类型,假设我们要返回我们的SobUser对象,那么就把这个bean类扔进去 -->
<select id="selectBlog" resultType="com.sunofbeaches.domain.SobUser">
<!-- sql语句,后面这个是参数 也就是从传递过来的参数中拿到username,根据这个来chaxun-->
select * from sob_user where username = #{username}
</select>
</mapper>
接着还有一个bean类:
package com.sunofbeaches.domain;
public class SobUser {
public int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
private String username;
private String password;
private String email;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "SobUser [id=" + id + ", username=" + username + ", password=" + password + ", email=" + email + "]";
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
好啦,接下来真的是查询了,我们创建一个测试类的,用main作为入口,在web开发里的web.xml作为入口,这里我们先针对javase项目去使用mybatis。
package com.sunofbeaches.test;
import java.io.IOException;
import java.io.InputStream;
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 com.sunofbeaches.domain.SobUser;
public class MyBatisTest {
public static void main(String[] args) throws IOException {
//通过配置文件创建SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//sqlSessionFactory拿到SqlSession
SqlSession openSession = sqlSessionFactory.openSession();
//查询一个数据出来,第一个参数是唯一标识符,第二个是sql语句里的参数
SobUser sobUser = openSession.selectOne("org.mybatis.example.SobUserMapper.selectSobUser", "BillGates");
System.out.println(sobUser);
openSession.close();
}
}
还要配置一下Mapper的地址,也就是我们那个
然后跑起来,就有了这样的结果:
MyBatis接口式编程
前面我们已经实现了一个Helloworld的小例子,但是有个弊端,就是我们查询的时候,传参数是个Ojbect类型,也就是传什么东西都可以,那么我们现在通过接口,定义好我们的参数和返回值。再由具体的类去实现查询即可,调用者不用管里面的实现逻辑。
首先我们定义接口:
修改SobUserMapper文件
package com.sunofbeaches.test;
import java.io.IOException;
import java.io.InputStream;
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 com.sunofbeaches.dao.ISobUserMapper;
import com.sunofbeaches.domain.SobUser;
public class MyBatisTest {
public static void main(String[] args) throws IOException {
//通过配置文件创建SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//sqlSessionFactory拿到SqlSession
SqlSession openSession = sqlSessionFactory.openSession();
//重点:
//这次我们获取到Mapper,然后再去调用方法即可
ISobUserMapper mapper = openSession.getMapper(ISobUserMapper.class);
SobUser sobUserByName = mapper.getSobUserByName("BillGates");
System.out.println(sobUserByName);
//end
openSession.close();
}
}
运行,我们得到一样的结果,把内容查询出来了!
SobUser [id=1, username=BillGates, password=null, email=test@sunofbeaches.com]
MyBatis全局配置文件
关于配置,文档里面有详细的说明,主要是Mapper的配置和mybatis-config.xml的配置
properties标签
<properties resource="" url="">
</properties>
properties里有两个参数,这两个参数用来指定资源路径的。
resource是指定class路径下的,而url用于指定网络路径或者磁盘上的路径。
我们比较常用的是用来引用数据库的配置,比如说前面我们是直接配置的,接下来我们把数据库的配置文件抽取出来,独立成一个dbconfig.properties文件
怎么引用呢?
这样子就可以使用了,以后呢就不需要修改这个配置文件了,如果数据库的配置变了,直接修改数据库的配置文件即可。
详情内容可以去看文档!
Settings
关于设置项有很多,大家需要参考文档,看文档里头的说明,这里的话我们举个例子,比如说,我们java里的命令是userName,而数据库里可能是user_name,如果在没有配置的情况下,默认是匹配不上的。如果我们开启一个设置项:
mapUnderscoreToCamelCasEenables,这个设置项的描述是:Eenables automatic mapping from classic database column names A_COLUMN to camel case classic Java property names aColumn.
把数据库中的字段,映射成JavaBean中的成员时,转在驼峰命名法,上面举了一个例子,在数据库中的字段是A_COLUMN,在javaBean中的成员则是aColumn,这样子就可以解决前面我们那个问题了。
默认值是false
我们怎么修改呢?
typeAliases别名
我们在写sql语句就知道别名了,这里的别名是用来干嘛的呢?
A type alias is simply a shorter name for a Java type. It’s only relevant to the XML configuration and simply exists to reduce redundant typing of fully qualified classnames.
比如说我们的Mapper:
每次我们都写全类名,觉得累不累呢,如果方法多的时候,要写挺多的,对不对。 那么我们可以起个别名来简化一下。 怎么指定别名呢?在mybatis的配置文件下:
使用:我们指定了别名以后就不需要写那么长的内容了,我们回到Mapper的配置文件里:
这样子直接修改,是可以跑起来了,我们就不需要写全类名了! 但这么写,也要写很多代码,有没有更好的办法呢?有-批量起别名
同样的,如这样起别名的话,默认就有一个类名的别名,别名不分大小写,你爱怎么写怎么写吧。 但是大家有没有发现什么问题?用package批量生成别名的话,假设名字冲突呢?比如说在这个包的下面还有一个子包,包里面有一个跟外面相同的类名,这个时候怎么办呢? 当然是手动指定别名啦! 我们可以通过注解的形式来解决这个问题,指定别名:
有一些别名了,是已经预置好的,比如下:
起别名的时候注意一下,不要跟预置的别名冲突。
environments
环境s
这玩意有什么用呢,翻译过来是环境的意思。
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="..." value="..."/>
</transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
以上是复制自文档的内容,从上面我们可以看到外层标签是environments,里面是单独的environment标签,换句话话,我们可以配置多个环境。
那么,这个配置是有什么用的呢?
在我们的实际开发中,我们有自己的开发环境,有测试环境,有上线的正式环境。我们配置好,在不同的时期使用不同的环境即可。
注意:environment标签里必须包含着dataSource和transactionManager否则会报错的呢!
报错了吧!
不过还好,开发工具自动帮助我们填充内容,这就是开发工具的好处呀,坏处就是离开了开发工具,基本上有代码短板的现象。
environment的id呢表示当前这个环境配置的唯一标识
假设我们这里有两个环境,一个是开发环境,一个是测试环境,我们怎么样指定当前的环境呢?
很简单:
<!--其实就是这个default用来指定当前使用哪个环境-->
<environments default="test">
<environment id="test">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${test.driver}"/>
<property name="url" value="${test.url}"/>
<property name="username" value="${test.user}"/>
<property name="password" value="${test.password}"/>
</dataSource>
</environment>
<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.user}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
这里面这个事物管理JDBC其实是一个别名,它是怎么对应的呢,我们可以看一下Configuration.
org.apache.ibatis.session.Configuration
这里面的话注册了很多别名。
我们跟Spring整合的时候,我们就会把事物管理交给Spring了。单独使用的话直接复制官方文档的内容即可。
多数据库厂商的支持
databaseldProvider,这样就解决了mybatis在移植性上面的问题
<databaseIdProvider type="DB_VENDOR">
<property name="SQL Server" value="sqlserver"/>
<property name="DB2" value="db2"/>
<property name="Oracle" value="oracle" />
</databaseIdProvider>
以上是文档里的例子,这是什么意思呢?
首先
<databaseIdProvider type="DB_VENDOR">
</databaseIdProvider>
这是一个固定写法
至于DB_VENDOR这个,其实也是个别名,可以看前面的说明去Configuration里找到对应的内容。
其实Vendor我们就知道这是个定制的,可扩展的了,如果有做过AOSP就知道了,一般厂商自己定义的东西就放在vendor目录下面。
那怎么使用呢?
第一步:
<databaseIdProvider type="DB_VENDOR">
<property name="MYSQL" value="mysql"/>
<property name="ORACLE" value="oracle"/>
</databaseIdProvider>
第二步:
在我们的语句中声明:
<select id="getEmployeeByName" resultType="EmployeeBean" databaseId="mysql">
SELECT * from tbl_employee WHERE last_name = #{lastName}
</select>
<select id="getEmployeeByName" resultType="EmployeeBean" databaseId="oracle">
SELECT * from tbl_employee WHERE last_name = #{lastName}
</select>
以上两条语句是一样的,假设我们的语句因为数据库平台不一样的时候,就会根据不同的id去执行了。
为什么会知道当前是什么数据库呢?因为api里是有接口获取的,而各个数据库平台的厂商要实现里面的方法,这样子就可以知道是什么数据库平台了,而对应地去执行sql语句。
Mapper
mapper是映射的意思,我们先说明一下mapper里面的属性
url引用的是硬盘上的文件,或者网络文件
官方的例子:
<!-- Using url fully qualified paths -->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/BlogMapper.xml"/>
<mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
resource的话,从我们的demo里就使用了,一般来说,我会创建一个文件夹用于存放,而文件夹的报名和映射的类名报名一样。而对应的mapper名字一样。
如下:
class属性的话,注册类的全路径名称即可,但是有一个前提条件,就是mapper.xml和类要放在同一样的包名下,前面我们已经放到同一样的包明了,所以我们这么写:
也是可以查询成功了。
还有一种写法就是用注解+类的形式,不写mapper.xml文件了
package com.sunofbeaches.dao;
import com.sunofbeaches.beans.EmployeeBean;
import org.apache.ibatis.annotations.Select;
/**
* Created by TrillGates on 2018/12/8.
*/
public interface EmployeeManagerAnnotation {
@Select("select * from tbl_employee where last_name = #{lastName}")
EmployeeBean getEmployeeByName(String lastName);
}
注册:
那什么时候用注解,什么时候用xml来配置呢?
简单的推荐使用注解,复杂的推荐使用配置文件。
每添加一个mapper就要写这一样个,这不是很麻烦吗?
其实可以全部一起注册,把某个包下面的mapper全部注册
映射文件详解
对应的官方文档是:https://www.mybatis.org/mybatis-3/sqlmap-xml.html
期中有一个过时了,我们就不去看了。
先看一下增删改吧,也就是insert delete update
首先,创建一个类:
package com.sunofbeaches.dao;
import com.sunofbeaches.beans.EmployeeBean;
/**
* Created by TrillGates on 2018/12/9.
*/
public interface EmployeeAction {
void insert(EmployeeBean employeeBean);
void update(EmployeeBean employeeBean);
void delete(EmployeeBean employeeBean);
}
再创建一个mapper,同名的mapper.xml然后把名称空间指向上面这个接口
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sunofbeaches.dao.EmployeeAction">
<!--void insert(EmployeeBean employeeBean);-->
<insert id="insert">
INSERT INTO tbl_employee(last_name,email,gender) VALUES (#{lastName},#{email},#{gender})
</insert>
<!--void update(EmployeeBean employeeBean);-->
<update id="update">
UPDATE tbl_employee SET last_name=#{lastName} , email=#{email} , gender=#{gender} WHERE id = #{id}
</update>
<!--void delete(EmployeeBean employeeBean);-->
<delete id="delete">
delete FROM tbl_employee WHERE id=#{id}
</delete>
</mapper>
测试:
package com.sunofbeaches.test;
import com.sunofbeaches.beans.EmployeeBean;
import com.sunofbeaches.dao.EmployeeAction;
import com.sunofbeaches.utils.LogUtils;
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 java.io.InputStream;
/**
* Created by TrillGates on 18/7/21.
*/
public class DBTest {
private static final String TAG = "DBTest";
public static void main(String[] args) throws Exception {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
LogUtils.d(TAG, "sqlSessionFactory " + sqlSessionFactory);
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
EmployeeAction mapper = sqlSession.getMapper(EmployeeAction.class);
EmployeeBean bean = new EmployeeBean();
// bean.setLastName("Bill");
// bean.setEmail("bill@gmail.com");
// bean.setGender("1");
//mapper.insert(bean);
// bean.setLastName("Test");
// bean.setEmail("test@gmail.com");
// bean.setGender("0");
bean.setId(1);
// mapper.update(bean);
mapper.delete(bean);
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
}
}
结果:
Mapper接口方法里的参数
我们的xml映射文件里的sql语句是怎么获取到参数的呢?
比如说,我们通过id去删除employee
<!-- void deleteById(Integer id);-->
<delete id="deleteById">
DELETE FROM tbl_employee WHERE id=#{id}
</delete>
我们通过一个#{字段名称}获取到id值
其实mybatis是这样子处理的
当方法是一个参数的时候,直接获取即可。如上,如果我们使用
<!-- void deleteById(Integer id);-->
<delete id="deleteById">
DELETE FROM tbl_employee WHERE id=#{idasdfasdf}
</delete>
#{随便输入东西}也是可以获取到id的值的,可以去试一下哈,这里我就不试了,再删除我就没内容了哈。
当方法多个参数的时候:
<!-- void getEmployeeByIdAndLastName(Integer id, String lastName);-->
<select id="getEmployeeByIdAndLastName" resultType="com.sunofbeaches.beans.EmployeeBean">
SELECT * FROM tbl_employee WHERE id=#{id} and last_name=#{lastName}
</select>
假如我们这么写,肯定报错:
那怎么办呢?看报错信息,有两个param呢!
我们改成这样子:
<!-- void getEmployeeByIdAndLastName(Integer id, String lastName);-->
<select id="getEmployeeByIdAndLastName" resultType="com.sunofbeaches.beans.EmployeeBean">
SELECT * FROM tbl_employee WHERE id=#{param1} and last_name=#{param2}
</select>
查询出来了,可是我用的参数是param1,param2,不好看呀,怎么办呢?
其实呀,多个参数的时候 ,mybatis把参数封装成了一个集合,key默认是param1,param2
我们也是可以指定的,为了方便起见,我们可以这么做:
package com.sunofbeaches.dao;
import com.sunofbeaches.beans.EmployeeBean;
import org.apache.ibatis.annotations.Param;
/**
* Created by TrillGates on 2018/12/9.
*/
public interface EmployeeAction {
void insert(EmployeeBean employeeBean);
void update(EmployeeBean employeeBean);
void delete(EmployeeBean employeeBean);
void deleteById(Integer id);
EmployeeBean getEmployeeByIdAndLastName(@Param("id") Integer id, @Param("lastName") String lastName);
}
映射文件写成这样子:
<!-- void getEmployeeByIdAndLastName(Integer id, String lastName);-->
<select id="getEmployeeByIdAndLastName" resultType="com.sunofbeaches.beans.EmployeeBean">
SELECT * FROM tbl_employee WHERE id=#{id} and last_name=#{lastName}
</select>
再来试试看运行结果如何:
查到了吧!
还可以怎么解决呢?多个参数转成一个参数呗,保存成一个Map对不对。反正都要转成Map集合的。
那我们这样写好了:
EmployeeBean getEmployeeByMap(Map<String, Object> map);
<!-- EmployeeBean getEmployeeByMap(Map<String, Object> map);-->
<select id="getEmployeeByMap" resultType="com.sunofbeaches.beans.EmployeeBean">
SELECT * FROM tbl_employee WHERE id=#{id} and last_name=#{lastName}
</select>
假设参数是List怎么获取呢?如果是Array下面的参数怎么获取呢?
举例子吧:
EmployeeBean getEmployeeByList(List<Object> params);
映射文件这样写:
<!-- EmployeeBean getEmployeeByList(List<String> params);-->
<select id="getEmployeeByList" resultType="com.sunofbeaches.beans.EmployeeBean">
SELECT * FROM tbl_employee WHERE id=#{list[0]} and last_name=#{list[1]}
</select>
运行结果:
EmployeeBean{id=3, lastName='Bill', email='bill@gmail.com', gender='1'}
数组同理的,这里就不写去写例子了。
其他的看文档吧,哈哈,就写到这里了!