一、MyBatis框架基本使用
一、 MyBatis简介
1.MyBatis由来
MyBatis 本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis。2013年11月迁移到Github。
iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQLMaps和Data Access Objects(sDAO)
2.应用范围
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录
3.主要特点:
· 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
· 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql基本上可以实现我们不使用数据访问框架可以实现的所有功能,或许更多。
· 解除sql与程序代码的耦合:通过提供DAL层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
· 提供映射标签,支持对象与数据库的orm字段关系映射
· 提供对象关系映射标签,支持对象关系组建维护
· 提供xml标签,支持编写动态sql。
4.总体流程
1)加载配置并初始化(加载配置文件)
(2)接收调用请求
(3)处理操作请求(为SQL的ID和传入参数对象)
(A)根据SQL的ID查找对应的MappedStatement对象。
(B)根据传入参数对象解析MappedStatement对象,得到最终要执行的SQL和执行传入参数。
(C)获取数据库连接,根据得到的最终SQL语句和执行传入参数到数据库执行,并得到执行结果。
(D)根据MappedStatement对象中的结果映射配置对得到的执行结果进行转换处理,并得到最终的处理结果。
(E)释放连接资源。
(4)返回处理结果将最终的处理结果返回。
二、基本配置
1.引入jar包
核心jar包
Mybatis-3.2.8.jar
相关依赖 |
<!-- mybatis核心jar包 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.2.8</version> </dependency> |
辅助jar包
因为使用mybatis框架后执行过程无法查看,所以在开发阶段为了方便调试需要使用
debug级别的Log4j将代码的执行过程显示出来,也可以查看sql语句
slf4j-log4j12.jar |
<!-- slf4j-log4j12 依赖 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.5</version> </dependency> |
2.配置mybatis.xml文件
mybatis.xml是 Mybatis的大脑,是重要的配置文件
1).主要配置jdbc环境的配置
configuration 配置
environment环境变量
transactionManager 事务管理器
dataSource 数据源
2).注册mapper.xml
<mappers>
<!-- 注册Mapper.xml文件 类路径从src出来 -->
<mapperresource="cn/et/fuqiang/helloworld/myUserMapper.xml"/>
</mappers>
mybatis configuration |
<?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> <!-- 指定jdbc的配置文件位置 --> <propertiesresource="cn/et/fuqiang/helloworld/jdbc.properties"></properties> <!-- 设置类别名 方便mapper设置返回类型--> <typeAliases> <!-- 两种设置返回类型的方法 --> <!-- 方法一 设置返回类型 type类的路径 alias 要使用的类别名 在TypeAliasRegistry.class类中查看默认设置的类别名 --> <typeAliastype="cn.et.fuqiang.helloworld.User"alias="myUser"/> <!-- 方法二 使用默认的扫包方式 ,设置要扫包的路径,mybatis会默认把包下面的所有类,以类名首字母小写的方式设置别名, (较为简单方便) 使用时可以直接以首字母小写去使用 --> <package name="cn.fuqiang.entity"/>
</typeAliases> <!-- 配置jdbc环境 --> <environmentsdefault="development"> <environmentid="development"> <transactionManagertype="JDBC"/> <!-- 配置数据库连接信息 el表达式${}获取--> <dataSourcetype="POOLED"> <propertyname="driver"value="${driverClass}"/> <propertyname="url"value="${url}"/> <propertyname="username"value="${user}"/> <propertyname="password"value="${password}"/> </dataSource> </environment> </environments>
<!-- 设置mapper文件路径 --> <mappers> <!-- 注册Mapper.xml文件 类路径从src出来 --> <mapperresource="cn/et/fuqiang/helloworld/myUserMapper.xml"/> </mappers>
</configuration> |
3.Sql语句的配置文件 Mapper.xml
1).指定namespace
为这个mapper指定一个唯一的namespace,namespace的值习惯上设置成包名+sql映射文件名,这样就能够保证namespace的值是唯一的
例如namespace="me.gacl.mapping.userMapper"就是me.gacl.mapping(包名)+userMapper(userMapper.xml文件去除后缀)
<mapper namespace="myuser">
……
</mapper>
2).在mapper标签中可以写想要执行的SQL语句主要标签有
<sql id="" ></sql>
<resultMaptype="" id=""></resultMap>
<insertid=""></insert>
<deleteid=""></delete>
<updateid=""></update>
<selectid=""></select>
配置mapper.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,namespace的值习惯上设置成包名+sql映射文件名,这样就能够保证namespace的值是唯一的 例如namespace="me.gacl.mapping.userMapper"就是me.gacl.mapping(包名)+userMapper(userMapper.xml文件去除后缀) --> <mapper namespace="myuser"> <!-- 在select标签中编写查询的SQL语句,设置select标签的id属性为getUser,id属性值必须是唯一的,不能够重复 使用parameterType属性指明查询时使用的参数类型,resultType属性指明查询返回的结果集类型 resultType="me.gacl.domain.User"就表示将查询结果封装成一个User类的对象返回 User类就是users表所对应的实体类 --> <!-- 根据id查询得到一个user对象 parameterType 传入的参数可以是一个任何类型 --> <selectid="selectUserById"parameterType="int"resultType="java.util.Map">
select * from myuser where userid=#{id} </select>
<insertid="insertUserByMap"parameterType="java.util.Map">
<!--selectKey是插入语句,和修改语句中特有的标签 keyProperty key的名字 order BEFORE/AFTER 在insert语句之前或者之后 resultType 查询语句返回的类型 --> <selectKeykeyProperty="userid"order="BEFORE"resultType="int"> select nvl(max(userid),0)+1 from myuser </selectKey> <!-- 从map中获取值 #{key}获取对应的值 --> insert into myuser(userid,username,userage) values(#{userid},#{username},#{userage}) </insert>
<deleteid="deleteUserById"parameterType="java.lang.Integer">
delete from myuser where userid=#{id} </delete>
<updateid="updateUserByMap"> update myuser set username=#{username},userage=#{userage} whereuserid=#{userid} </update> <!-- 练习使用typeAiase标签(在mybatis配置文件中使用) 创建类别名设置返回类型 默认的别名在TypeAliasRegistry.class类中查看--> <selectid="selectUserGetUser"resultType="myUser"> select * from myuser where userid=#{id} </select> </mapper> |
下面会常用的标签详细的解释
4.java代码执行sql
1).获取一个可以执行映射文件这种sql的sqlSession
第一种方法 |
//mybatis的配置文件 String resource = "mybatis.xml"; //使用类加载器加载mybatis的配置文件(它也加载关联的映射文件) InputStream is = 当前类.class.getResourceAsStream(resource); //构建sqlSession的工厂 SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is); //创建能执行映射文件中sql的sqlSession SqlSession session = sessionFactory.openSession(); |
第二种方法 |
//mybatis的配置文件 String resource = "mybatis.xml"; //使用MyBatis提供的Resources类加载mybatis的配置文件(它也加载关联的映射文件) Reader reader = Resources.getResourceAsReader(resource); //构建sqlSession的工厂 SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader); //创建能执行映射文件中sql的sqlSession SqlSession session = sessionFactory.openSession(); |
2.执行sql语句的方式
使用session.insert/update/delete/select()执行方法
SqlSession session = getSession();
session.insert/update/delete/select ();
|
这只是最基础的用法,真正的实战中使用接口映射完成 |
三、mapper.xml配置文件中常用的sql标签
1.select标签属性简介
<select resultType="hashmap" resultMap="USER_RESULT_MAP" flushCache="false" useCache="true" timeout="10000" fetchSize="256" statementType="PREPARED" resultSetType="FORWORD_ONLY" ></select>
|
2.delete标签
<delete id id(必须配置) parameterType=""
parapeterType(可选配置,默认由mybatis自动选择处理)
databaseId="" 取值范围oracle|mysql等,表示数据库厂家,元素内部可通过`<if test="_databaseId = 'oracle'">`来为特定数据库指定不同的sql语句
lang=""
statementType="STATEMENT" statementType(可选配置) timeout="" timeout(可选配置) flushCache="true" flushCache(可选配置)
parameterMap=""
></delete> |
|
3.inert标签
<insertid="saveUserByMap"
parameterType ,入参的全限定类名或类型别名 keyColumn ,设置数据表自动生成的主键名。对特定数据库(如PostgreSQL),若自动生成的主键不是第一个字段则必须设置 keyProperty ,默认值unset,用于设置getGeneratedKeys方法或selectKey子元素返回值将赋值到领域模型的哪个属性中 useGeneratedKeys ,取值范围true|false(默认值),设置是否使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中。MySQL和SQLServer执行auto-generated key field,因此当数据库设置好自增长主键后,可通过JDBC的getGeneratedKeys方法获取。但像Oralce等不支持auto-generated key field的数据库就不能用这种方法获取主键了 statementType ,取值范围STATEMENT,PREPARED(默认值),CALLABLE flushCache ,取值范围true(默认值)|false,设置执行该操作后是否会清空二级缓存和本地缓存 timeout ,默认为unset(依赖jdbc驱动器的设置),设置执行该操作的最大时限,超时将抛异常 databaseId ,取值范围oracle|mysql等,表示数据库厂家,元素内部可通过`<if test="_databaseId = 'oracle'">`来为特定数据库指定不同的sql语句
> </insert> |
4.update标签
<updateid="" parameterType ,入参的全限定类名或类型别名 keyColumn ,设置数据表自动生成的主键名。对特定数据库(如PostgreSQL),若自动生成的主键不是第一个字段则必须设置 keyProperty ,默认值unset,用于设置getGeneratedKeys方法或selectKey子元素返回值将赋值到领域模型的哪个属性中 useGeneratedKeys ,取值范围true|false(默认值),设置是否使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中。MySQL和SQLServer执行auto-generated key field,因此当数据库设置好自增长主键后,可通过JDBC的getGeneratedKeys方法获取。但像Oralce等不支持auto-generated key field的数据库就不能用这种方法获取主键了 statementType ,取值范围STATEMENT,PREPARED(默认值),CALLABLE flushCache ,取值范围true(默认值)|false,设置执行该操作后是否会清空二级缓存和本地缓存 timeout ,默认为unset(依赖jdbc驱动器的设置),设置执行该操作的最大时限,超时将抛异常 databaseId ,取值范围oracle|mysql等,表示数据库厂家,元素内部可通过`<if test="_databaseId = 'oracle'">`来为特定数据库指定不同的sql语句
></update>
|
5.selectKey标签
selectKey标签只在insert标签和update标签中存在
作用:在insert元素和update元素中插入查询语句。 其属性如下: keyProperty ,默认值unset,用于设置getGeneratedKeys方法或selectKey子元素返回值将赋值到领域模型的哪个属性中 resultType ,keyPropety所指向的属性类全限定类名或类型别名 order属性 ,取值范围BEFORE|AFTER,指定是在insert语句前还是后执行selectKey操作 statementType ,取值范围STATEMENT,PREPARED(默认值),CALLABLE
|
实例 在插入的时候oracle没有自增可以用子查询或查询序列 |
<insertid="saveUserByMap">
<selectKeykeyProperty="userid"order="BEFORE"resultType="int"> select nvl(max(userid),0)+1 from myuser </selectKey> insert into myuser(userid,username,userage) values(#{userid},#{username},#{userage}) </insert> |
6.重用sql标签
<sqlid="userColumns">id,username,password</sql>
这个 SQL 片段可以被包含在其他语句中
<selectid="selectProjectList"paramertType="int"resultType="hashmap">
SELECT
<includerefid="userColumns"/>
FROM
t_project_002_project_info
</select>
四、sql语句的编写与参数的传递
Mapper.xml中编写sql语句
与标准的sql语句一样
如:Select * fromtablename where column=#{0}/${0}
1.获取变量
从sql语句中获取参数有多中方式
不能根据索引取值因为el表达式会把索引当运算的数字
el表达式
${} 只能用在形参中指定的名称来获取 和 param1 名字
(获取值得方法相当于字符串的拼接 如果是字符串的话要用引号)
ognl表达式
#{} 可以根据传入的变量名来获取值,也可以根据上面两种方式 (获取值得方法是防注入的,?会用问号代替)
默认是根据形参的索引从0开始
2.可以设置
parameterType 设置传入的参数类型
可以不设置直接使用即可
3.如果是查询语句需要设置返回类型resultType
(在TypeAliasRegistry.class中设置了许多类别名,填写类型的时候可以直接写别名)
4.java代码传入变量
//@Test public void updateUserByMap() { SqlSession session = getSession(); Map<String,Object> updateMap = new HashMap<String,Object>(); updateMap.put("userid", 1); updateMap.put("username","wfq666"); updateMap.put("userage", 5858518); int update = session.update("updateUserByMap",updateMap); System.out.println(update); session.commit();
} //@Test public void deleteUserById() { SqlSession session = getSession(); int delete = session.delete("deleteUserById", 1); System.out.println(delete); session.commit(); } //@Test public void insertUserByMap() { SqlSession session = getSession(); //创建需要插入的值,key是列名,value 是值 Map<String,Object> insertMap = new HashMap<String,Object>(); //新插入信息只需要写入用户名和年龄,id使用selectKey标签添加 insertMap.put("username","wfq2"); insertMap.put("userage", 100); int insert = session.insert("myuser.insertUserByMap",insertMap); System.out.println(insert); session.commit(); } //@Test public void selectUserById() { SqlSession session = getSession(); /** * 映射sql的标识字符串, * myuser.selectUser是myUserMapper.xml文件中mapper标签的namespace属性的值, * getUser是select标签的id属性值,通过select标签的id属性值就可以找到要执行的SQL */ //执行查询返回一个唯一user对象的sql Map<String,Object> map= session.selectOne("myuser.selectUserById", 1); System.out.println(map); }
@Test public void selectUserGetUser() { SqlSession session = getSession(); //执行查询返回一个唯一user对象的sql User user= session.selectOne("myuser.selectUserGetUser", 1); System.out.println(user); } |
所有代码实现
Mybatis主要配置文件
mybatis.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> <!-- 指定jdbc的配置文件位置 --> <propertiesresource="cn/et/fuqiang/helloworld/jdbc.properties"></properties> <!-- 设置类别名 方便mapper设置返回类型--> <typeAliases> <!-- 两种设置返回类型的方法 --> <!-- 方法一 设置返回类型 type类的路径 alias 要使用的类别名 在TypeAliasRegistry.class类中查看默认设置的类别名 --> <typeAliastype="cn.et.fuqiang.helloworld.User"alias="myUser"/>
<!-- 方法二 直接扫描某个包让容器自己起别名 <package name=""/>--> </typeAliases> <!-- 配置jdbc环境 --> <environmentsdefault="development"> <environmentid="development"> <transactionManagertype="JDBC"/> <!-- 配置数据库连接信息 --> <dataSourcetype="POOLED"> <propertyname="driver"value="${driverClass}"/> <propertyname="url"value="${url}"/> <propertyname="username"value="${user}"/> <propertyname="password"value="${password}"/> </dataSource> </environment> </environments>
<!-- 设置mapper文件路径 --> <mappers> <!-- 注册表Mapper.xml文件 类路径从src出来 --> <mapperresource="cn/et/fuqiang/helloworld/myUserMapper.xml"/> </mappers>
</configuration>
|
Jdbc.properties
url=jdbc:oracle:thin:@localhost:1521:orcl user=mybatis password=mybatis driverClass=oracle.jdbc.OracleDriver |
Sql映射配置文件
myUserMapper.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,namespace的值习惯上设置成包名+sql映射文件名,这样就能够保证namespace的值是唯一的 例如namespace="me.gacl.mapping.userMapper"就是me.gacl.mapping(包名)+userMapper(userMapper.xml文件去除后缀) --> <mapper namespace="myuser"> <!-- 在select标签中编写查询的SQL语句,设置select标签的id属性为getUser,id属性值必须是唯一的,不能够重复 使用parameterType属性指明查询时使用的参数类型,resultType属性指明查询返回的结果集类型 resultType="me.gacl.domain.User"就表示将查询结果封装成一个User类的对象返回 User类就是users表所对应的实体类 --> <!-- 根据id查询得到一个user对象 parameterType 传入的参数可以是一个任何类型 --> <selectid="selectUserById"parameterType="int"resultType="java.util.Map">
select * from myuser where userid=#{id} </select>
<insertid="insertUserByMap"parameterType="java.util.Map">
<!--selectKey是插入语句,和修改语句中特有的标签 keyProperty key的名字 order BEFORE/AFTER 在insert语句之前或者之后 resultType 查询语句返回的类型 --> <selectKeykeyProperty="userid"order="BEFORE"resultType="int"> select nvl(max(userid),0)+1 from myuser </selectKey> <!-- 从map中获取值 #{key}获取对应的值 --> insert into myuser(userid,username,userage) values(#{userid},#{username},#{userage}) </insert>
<deleteid="deleteUserById"parameterType="java.lang.Integer">
delete from myuser where userid=#{id} </delete>
<updateid="updateUserByMap"> update myuser set username=#{username},userage=#{userage} whereuserid=#{userid} </update> <!-- 练习使用typeAiase标签(在mybatis配置文件中使用) 创建类别名设置返回类型 默认的别名在TypeAliasRegistry.class类中查看--> <selectid="selectUserGetUser"resultType="myUser"> select * from myuser where userid=#{id} </select>
</mapper> |
用户实体
User |
package cn.et.fuqiang.helloworld;
public class User { private Integer userid; private String username; private Integer userage; public User() {} public User(Integer userid, String username, Integer userage) { this.userid =userid; this.username =username; this.userage =userage; } public Integer getUserid() { return userid; } public void setUserid(Integer userid) { this.userid =userid; } public String getUsername() { return username; } public void setUsername(String username) { this.username =username; } public Integer getUserage() { return userage; } public void setUserage(Integer userage) { this.userage =userage; } @Override public String toString() { return "User [userid=" + userid + ", username=" + username + ", userage=" + userage + "]"; }
}
|
运行测试类
HelloMyBatis |
package cn.et.fuqiang.helloworld;
import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map;
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 HelloMyBatis { public static SqlSession getSession() { //mybatis的配置文件 String resource = "mybatis.xml"; //使用类加载器加载mybatis的配置文件(它也加载关联的映射文件) InputStream is = HelloMyBatis.class.getResourceAsStream(resource); //构建sqlSession的工厂 SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is); //使用MyBatis提供的Resources类加载mybatis的配置文件(它也加载关联的映射文件) //Reader reader = Resources.getResourceAsReader(resource); //构建sqlSession的工厂 //SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader); //创建能执行映射文件中sql的sqlSession SqlSession session = sessionFactory.openSession(); return session; } public static SqlSession getSessionByResources() throws IOException { //mybatis的配置文件 String resource = "mybatis.xml"; //使用MyBatis提供的Resources类加载mybatis的配置文件(它也加载关联的映射文件) Reader reader = Resources.getResourceAsReader(resource); //构建sqlSession的工厂 SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader); //创建能执行映射文件中sql的sqlSession SqlSession session = sessionFactory.openSession(); return session; }
//@Test public void updateUserByMap() { SqlSession session = getSession(); Map<String,Object> updateMap = new HashMap<String,Object>(); updateMap.put("userid", 1); updateMap.put("username", "wfq666"); updateMap.put("userage", 5858518); int update = session.update("updateUserByMap",updateMap); System.out.println(update); session.commit();
} //@Test public void deleteUserById() { SqlSession session = getSession(); int delete = session.delete("deleteUserById", 1); System.out.println(delete); session.commit(); } //@Test public void insertUserByMap() { SqlSession session = getSession(); //创建需要插入的值,key 是列名,value 是值 Map<String,Object> insertMap = new HashMap<String,Object>(); //新插入信息只需要写入用户名和年龄,id使用selectKey标签添加 insertMap.put("username", "wfq2"); insertMap.put("userage", 100); int insert = session.insert("myuser.insertUserByMap", insertMap); System.out.println(insert); session.commit(); } //@Test public void selectUserById() { SqlSession session = getSession(); /** * 映射sql的标识字符串, * myuser.selectUser是myUserMapper.xml文件中mapper标签的namespace属性的值, * getUser是select标签的id属性值,通过select标签的id属性值就可以找到要执行的SQL */ //执行查询返回一个唯一user对象的sql Map<String,Object> map= session.selectOne("myuser.selectUserById", 1); System.out.println(map); }
@Test public void selectUserGetUser() { SqlSession session = getSession(); //执行查询返回一个唯一user对象的sql User user= session.selectOne("myuser.selectUserGetUser", 1); System.out.println(user); }
} |