MyBatis简介
1、MyBatis可以简化JDBC操作,实现数据的持久化
2、MyBatis是ORM产品,是ORM的一个实现。对象关系映射(Object Relational Mapping,简称ORM)是通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据库中。可以使操作数据库表变得和操作对象一样。
映射关系:对象与表名映射,对象的属性与表的属性映射
映射后每增加一个对象,被映射的表就会多一条数据
配置MyBatis
1、下载并导入jar包,mybatis.jar和数据库驱动jar包, mybatis.jar下载地址.
2、MyBatis是普通的Java项目,项目创建后首先要创建mapper.xml(在文件里把对象和表一一映射):增删改查标签,需要复制官方文档中的 2.15的代码
<?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:该mapper.xml映射文件的唯一标识-->
<mapper namespace="org.mybatis.example.BlogMapper">
<select id="selectBlog" resultType="Blog">
select * from Blog where id = #{id}
</select>
</mapper>
3、创建表和类
4、创建configure.xml配置文件,在里面添加数据库的信息和需要加载的映射文件,需要复制官方文档中的 2.12的代码
<?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值和environment的id 来指定MyBatis运行时的数据库环境-->
<environments default="development">
<!-- 开发环境(如自己的计算机) -->
<environment id="development">
<!-- 事务提交方式:
JDBC:利用JDBC方式处理事务(commit rollback close)
MANAGED:将事务交由其他组件去托管(spring,jobss),用完后会默认关闭连接,需要自己配置才不会关闭,代码如下:
<transactionManager type="MANAGED"/>
<property name="closeConnection" value="false"/>
-->
<transactionManager type="JDBC"/> <!-- 用什么方式处理事务 -->
<!-- 数据源类型:
UNPOOLED:传统的JDBC模式,每次访问数据库,都需要进行打开和关闭等数据库操作,比较消耗性能
POOLED:使用数据库连接池,有多个连接就能处理多个请求,用完后只需还回来,省略了数据库的打开和关闭,提高效率
JNDI:从tomcat中获取一个内置的数据库连接池()
-->
<dataSource type="POOLED">
<!-- 配置数据库信息 -->
<property name="driver" value="oracle.jdbc.OracleDriver"/> <!-- value里放数据库的驱动 -->
<property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:ORCL"/> <!-- 访问数据库的链接字符串 -->
<property name="username" value="scott"/>
<property name="password" value="tiger"/>
</dataSource>
</environment>
<!-- 真正的项目应该在发布的那台计算机上运行(实施计算机) -->
<environment id="implement">
<!-- .........-->.
</environment>
</environments>
<mappers>
<!-- 加载映射文件 -->
<mapper resource="chern/cn/studentMapper"/>
</mappers>
</configuration>
基础方式的增删改查
1、输入参数:如果是简单类型(8个基本类型+String),则可以使用任意占位符,即可在#{}里写任意名称,代码如下
<!--parameterType:输入参数类型 resultType:返回值类型
且mybatis规定parameterType输入参数和resultType输出参数在形式上只能有一个
如果是对象类型,则必须是对象的属性 #{属性名},代码如下
-->
<!--增-->
<insert id="addStudent" parameterType="chern.cn.Student">
insert into student(stuno,stuname,stuage,graname) values(#{stuNo},#{stuName},#{stuAge},#{graName})
</insert>
<!--删-->
<delete id="deleteStudentByStuno" parameterType="int">
delete from student where stuno = #{stuno}
</delete>
<!--改-->
<update id="updateStudentByStuno" parameterType="chern.cn.Student">
update student set stuname=#{stuName}, stuage=#{stuAge},graname=#{graName} where stuno=#{stuNo}
</update>
<!--查-->
<select id="queryPersonByStuno" resultType="chern.cn.Student" parameterType="int">
select * from student where stuno = #{stuno}
2、输出参数:如果返回值类型是一个对象(如Student),则无论返回一个、还是多个,在resultType都写成chern.cn.Student
3、如果使用的事务方式为JDBC,则需要手工commit提交,即session.commit();
4、所有的标签等,都必须有sql语句,但是sql参数值可选,
如:select * from student where stuno = #{xxx}中select * from student代表第一个参数,where stuno = #{xxx}代表第二个参数,代码如下
//java执行查询代码
//加载MyBatis配置文件(为了访问数据库)
//Connection - SqlSession操作MyBatis
//conf.xml -> reader
Reader reader = Resources.getResourceAsReader("conf");
//SqlSessionFactory - connection
//reader -> SqlSession
//通过SqlSessionFactoryBuilder().build()的第二个参数可以指定MyBatis运行时的数据库环境
//如SqlSessionFactoryBuilder().build(reader,"development")
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
//session - connection
SqlSession session = sessionFactory.openSession();
//session.selectOne("需要查询的SQL的namespace.id,"SQL的参数值")
String statement = "chern.cn.studentMapper.queryPersonByStuno";
Student student = session.selectOne(statement,1);
System.out.println(student);
session.close();
<!-- 对应映射文件的代码 -->
<mapper namespace="chern.cn.studentMapper">
<select id="queryPersonByStuno" resultType="chern.cn.Student" parameterType="int">
select * from student where stuno = #{stuno}
</select>
mapper动态代理方式的增删改查(MyBatis接口开发)
1、原则:约定优于配置,配置优于硬编码
2、各种方式
以配置项目的名字为例
硬编码方式:
abc.java
Configuration conf = new Configuration();
conf.setName("myProject");
配置方式:
abc.xml
<name>myProject</name>
约定:默认值设置为myProject
3、实现步骤
1)、基础环境:mybatis.jar、ojdbc.jar、conf.xml、mapper.xml
2)、约定的目标:省略掉statement,即根据约定直接定位出sql语句
a、接口,接口中的方法必须遵循以下规则
1、方法名和mapper.xml文件中标签的id值相同
2、方法的输入参数和mapper.xml文件中标签的parameterType类型一致(如果mapper.xml的标签中没有parameterType,则说明方法没有输入参数)
3、方法的返回值和mapper.xml文件中标签的resultType类型一致(如果没有返回值,则说明方法的返回值为void)
除了以上约定,要实现 接口中的方法 和 mapper.xml中sql标签一一对应,还需要:把namespace的值设置为接口的全类名(接口 – mapper.xml 一一对应)
约定的过程
1、根据 接口名 找到 mapper.xml文件(根据的是namespace=接口全类名)
2、根据 接口的方法名 找到 mapper.xml文件中的sql标签(方法名=sql标签Id值)
以上2点可以保证:当我们调用接口中的方法时,程序能自动定位到 某一个mapper.xml文件中的sql标签
习惯:一般我们把sql映射文件(mapper.xml) 和 接口放在同一个包中
可以通过接口的方法->sql语句
主要代码:
//主要是定义好StudentMapper接口后,在里面创建相应的方法。
//mapper.xml的代码
<mapper namespace="chern.mapper.StudentMapper">
<select id="queryPersonByStuno" resultType="student" parameterType="int">
select * from student where stuno = #{stuno}
</select>
//StudentMapper.java的代码
Student queryPersonByStuno(int stuno);
//main方法里的代码
Reader reader = Resources.getResourceAsReader("conf");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
SqlSession session = sessionFactory.openSession();
StudentMapper sessionMapper = session.getMapper(StudentMapper.class);
Student student = sessionMapper.queryPersonByStuno(1);//接口中的方法->sql语句
System.out.println(student);
session.close();
在main方法中通过session对象获取接口(session.getMapper(接口.class)),再调用该接口中的方法,程序会自动执行该方法对应的sql
优化
1、改配置信息
可以将配置信息 以key–value对的形式 单独放入db.properties文件(文件放在根目录里)中,然后再动态引入(在conf.xml的configuration标签下添加<properties resource="文件路径"/>
)
如:
//db.properties代码
driver=oracle.jdbc.OracleDriver
url=jdbc:oracle:thin:@127.0.0.1:1521:ORCL
username=scott
password=tiger
//conf.xml代码
<!-- 该标签放在<configuration>标签下 -->
<properties resource="db.properties"/>
<!-- 配置数据库信息 -->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
2、全局参数(在conf文件中设置)
代码如下:
<settings>
//<setting name="需要设置的参数" value="开启或关闭"/>如
<setting name="cacheEnabled" value="false"/>
</settings>
3、别名(在conf中配置)
a、设置单个别名
b、批量设置别名
代码如下:
<typeAliases>
<!--单个别名(别名忽略大小写)
<typeAlias type="chern.cn.Student" alias="student"/>
-->
<!--批量定义别名(别名忽略大小写),会自动将该包中的所有类批量定义别名:别名就是类名(不带包名的类名)-->
<package name="chern.cn"/>
</typeAliases>
除了自定义别名外,MyBatis还内置了一些常见类的别名,在这里就不一一列举了。
类型处理器(类型转换器)
1、MyBatis自带一些常见的类型处理器,如 int - number
2、自定义MyBatis类型处理器:java - 数据库(jdbc类型)
实例:
实体类Student: boolean stuSex
true:男
false:女
表student: number stuSex
1:男
0:女
自定义类型转换器(boolean - number)步骤:
a、创建转换器:实现TypeHandler接口(此接口有一个实现类BaseTypeHandler,所以也可以继承该实现类),主要代码
//BooleanAndIntConverter.java代码
public class BooleanAndIntConverter extends BaseTypeHandler<Boolean> {
//set:java -> 数据库(DB)
//get:数据库(DB)-> java
/**
* preparedStatement:PreparedStatement对象
* i:PreparedStatement对象操作参数的位置
* aBoolean:java值
* jdbcType:jdbc操作的数据库类型
*/
//java(boolean) -> DB(number)
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, Boolean aBoolean, JdbcType jdbcType) throws SQLException {
if(aBoolean){
preparedStatement.setInt(i,1);
}
else{
preparedStatement.setInt(i,0);
}
}
//DB(number) -> java(boolean)
@Override
public Boolean getNullableResult(ResultSet resultSet, String s) throws SQLException {
int sexnum = resultSet.getInt(s);
return sexnum == 1?true:false;
}
@Override
public Boolean getNullableResult(ResultSet resultSet, int i) throws SQLException {
int sexnum = resultSet.getInt(i);
return sexnum == 1?true:false;
}
@Override
//CallableStatement:存储过程
public Boolean getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
int sexnum = callableStatement.getInt(i);
return sexnum == 1?true:false;
}
}
b、配置conf.xml
<typeHandlers>
<typeHandler handler="chern.converter.BooleanAndIntConverter" javaType="Boolean" jdbcType="INTEGER"/>
</typeHandlers>
在做好以上配置后,我们还需要在studentMapper.xml进行进一步的配置。
如果类中属性 和 表中的字段 类型能够合理识别(String-varchar2),则可以使用resultType;否则使用resultMap(boolean-number)。
如果类中属性名 和 表中的字段名 能够合理识别(stuNo -stuno),则可以使用resultType;否则使用resultMap(id-stuno)。主要代码如下:
<select id="queryStudentByStunoWithConverter" resultMap="studentResult" parameterType="int">
select * from student where stuno = #{stuno}
</select>
<resultMap id="studentResult" type="student">
<!--分为主键(使用<id/>标签) 和 非主键使用<result/>标签)-->
<id property="stuNo" column="stuno"/>
<result property="stuName" column="stuname"/>
<result property="stuAge" column="stuage"/>
<result property="graName" column="graname"/>
<result property="stuSex" column="stusex" javaType="boolean" jdbcType="INTEGER"/>
</resultMap>