为什么学习Mybatis
Hibernate的核心是ORM,将表的记录和对象进行全自动映射,目标是消除SQL,但是对于复杂的查询,需要进行定制,我们需要精通HQL来满足要求.
Mybatis则将SQL语句写在配置文件中,实现SQL和Java分离,且SQL是可定制,由开发人员控制.
Mybait下载目录:https://github.com/mybatis/mybatis-3/releases
Mybatis- Helloworld
1.根据配置文件(全局配置文件)创建SQLSessionFactory对象,这个文件中有数据源的配置信息. myconfig.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>
<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://localhost:3306"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
</configuration>
2.创建SQL映射文件.eg: employee.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.dong.service.employeeMapper">
<select id="selectEmployee" resultType="com.dong.service.employee" >
select * from Blog where id = #{id}
</select>
</Mapper>
3.将SQL映射文件放入到全局配置文件.
<!-- 将写好的sql映射文件一定要写到全局配置文件myconfig.xml中 -->
<Mappers>
<Mapper resource="employee.xml"/>
</Mappers>
4.写代码:根据配置文件获取SQLSessionFactory -> 然后获取SQLSession ,表示SQL的一次会话,然后使用SQL的唯一标志来告诉mybatis执行哪个SQL语句,->关闭session.
package com.dong.controller;
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.dong.service.employee;
import com.dong.service.employeeMapper;
public class Mybatis {
public static void main(String[] args) throws IOException {
}
public void test() throws IOException {
String resource = "config/myconfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(inputStream);
//获取sqlSession实例,可以直接执行已经映射的sql语句
SqlSession openSession = null ;
try {
openSession = sqlSessionFactory.openSession();
employee emp = openSession.selectOne("org.mybatis.example.employeeMapper.selectEmp", 1); //这个时候我们的namespace是一个随便写的值,com.dong.service.employeeMapper为namespace, selectEmployee是sql标识id.
System.out.println(emp.toString());
} finally {
openSession.close();
}
}
}
问题:
在上面的SQL语句中,使用selectOne需要一个id值,但没有显示的限制传递的类型,也没有进行判断,有可能导致查询不到,eg: 传递“ad”,而不是数字,因此Mybatis使用更高级的写法:
接口的方式,更安全:
1.创建接口. employeeMapper
package com.dong.service;
import java.util.Map;
public interface employeeMapper {
public employee getEmployee(Integer id);
}
2.在Mapper文件中,将命名空间改为接口的全类名,然后将SQL的id改为方法名.
<?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.dong.service.employeeMapper">
<select id="getEmployee" resultType="com.dong.service.employee" databaseId="mysql" >
select * from Blog where id = #{id}
</select>
</Mapper>
3.写代码
public void test1() throws IOException {
String resource = "config/myconfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(inputStream);
SqlSession openSession = null;
//获取sqlSession实例,可以直接执行已经映射的sql语句
try {
openSession = sqlSessionFactory.openSession();
employeeMapper Mapper = openSession.getMapper(employeeMapper.class);
employee employee = Mapper.getEmployee(1);
System.out.println(employee.toString());
openSession.commit();
}finally {
openSession.close();
}
}
每个接口方法都对应Mapper.xml中的一个映射,
SqlSession 和 Connector是非线程安全的,每次使用我们最好创建一个新的SQLSession.
Mapper没有接口的实现类,Mybatis会生成一个代理.
配置文件
配置文件:全局配置文件, 包含数据库信息,事务管理,系统运行环境,注意全局配置文件可以没有,Mybatis使用默认的配置.eg: myconfig.xml
SQL映射文件:必须有,保存了每一个SQL语句的映射信息.eg:eployeeMapper.xml
Mybatis 全局配置文件
注意:这些标签都不需包含在<Configuration>..</Configuraion>中.
properteis:用来引入外部配置文件
resource:用来引入类路径下配置文件
uri:引入网络路径或者磁盘路径下的资源
<properties resource="db.propreties"></properties>
settings:包含很多设置项,设置项直接影响mybatis的运行时行为,
settting:用于设置属性,
setting name:属性名 value 属性值.eg:开启驼峰命令识别
<settings>
<setting name="MapUnderscoreToCamelCase" value="true"/>
</settings>
typeAliases :别名处理器, Java类型起别名,使得引用方便,注意别名不区分大小写.
typeAlis:为某个Java类型起别名,
type:指定想要其别的全类名,默认别名是类名小写.
alias:新的别名
<typeAliases>
<typeAlias type="com.dong.service.employee" alias="emp"/>
</typeAliases>
package:为某个包下类批量其别名,
name:当前包的所有类其别名,默认别名为类名小写.
alias:新的别名
在批量起别名的情况下,使用注解@Alias()在特定的类上指定别名
<typeAliases>
<package name="com.dong.controller"/>
</typeAliases>
typeHandlers : 进行数据库类型和Java类型映射
plugins: 进行插件,mybatis可以进行拦截,拦截使用插件进行,
environments:进行环境配置,mybatis可以配置多种环境,default指定使用某种环境,可以快速切换环境.
environment:配置一个具体的环境信息,必须有两个标签,即dataSource ,transcationManager
environment id: 代表当前环境的唯一标识.
transcationManager:配置事务管理器,:
type:JDBC | MANAGED,也可以自定义事务管理器,
dataSource:数据源,
type:UNPOOLED | POOLED | JNDI,也可以自定义数据源,
<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>
databaseIdProvider:Mybatis可执行不同的SQL语句根据不同的数据库厂商,支持多数据库厂商,eg:Oracle
type:"DB_VENDOR",作用:得到数据库厂商的标识. MYSQL, Oracle,SQL Server,可以对不同的数据库厂商起别名.
<databaseIdProvider type="DB_VENDOR">
<!-- 为不同的数据库厂商起别名 -->
<property name="MySQL" value="mysql"/>
<property name="Oracle" value="oracle"/>
<property name="SQL Server" value="sqlserver"/>
</databaseIdProvider>
使用方式在Mapper文件中,select标签中使用 databaseId="mySQL"属性来设置使用哪个数据库厂商,值为别名.
<select id="getEmployee" resultType="com.dong.service.employee" databaseId="mysql" >
select * from Blog where id = #{id}
</select>
Mappers:将SQL映射注册到全局配置中
Mapper:注册SQL映射
resource:引入类路径下
url:应用网络路径|磁盘路径下
<!-- 将写好的sql映射文件一定要写到全局配置文件 -->
<Mappers>
<Mapper resource="employee.xml"/>
</Mappers>
package:批量注册, name: 具体包名, 需要将映射文件放在包的目录下,
<!-- 将写好的sql映射文件一定要写到全局配置文件 -->
<Mappers>
<package name="com.dong.Mappers"/>
</Mappers>
class:注册接口,
1.有映射文件,需要将配置文件放到接口同一目录下,配置文件的名字与接口同名;
<Mappers>
<Mapper class="com.dong.service.employeeMapper"/>
</Mappers>
2.没有映射文件, 直接在接口上写相应的注解@Select(SQL语句),然后再Mapper中进行注册,eg:employeeMapper接口
public interface employeeMapper {
@Select("selct * from table_name where id = #{id} ")
public employee getEmployee(Integer id);
}
全局配置文件,config.xml(名字随意)
<Mappers>
<Mapper class="com.dong.service.employeeMapper"/>
</Mappers>
注意:全局文件编辑也是有顺序的,
推荐比较重要的dao,写SQL映射文件,不重要的,简单的,为了快速开发,使用注解方式.
Mybatis映射文件
增删改查:
public interface employeeMapper {
public employee getEmployees2 (Map<String ,Object> Map);
public void addEmployee(employee emp);
public void updateEmployee(employee emp);
public void deleteEmployee(employee emp);
}
获取自增主键
Mybatis 支持自增主键,自增主键的获取,通过statement.getGenerateKeys(),
useGeneratedKeys="true":使用自增主键获取主键值策略,
keyProperty="xxx":指定对应的主键属性,也就是mybatis获取到主键值以后,将这个值封装到JavaBean的哪个属性.
由于主键自增,所以SQL语句不需要写主键,但在构建映射bean时,需要填写主键的值,可以使用null代替.
<insert id="addEmployee" parameterType="com.dong.service.employee" useGeneratedKeys="true" keyProperty="id">
insert into tbl_employee(last_name,email,gendar) values (#{lastName},#{email},#{gendar})
</insert>
Oracle:不支持自增,主键是从序列中获取,
插入时的主键是从序列中获取的,使用<selectKey>,进行查询主键语句, KeyProperty:将查询的主键封装到bean的哪个属性, order:"BEFROE",查主键的SQL是在前执行,"AFTER",在后执行,resultType:xxx,结果的类型.
keyProperty 也可使用AFTER,获取当前的序列值,但是之前的insert语句为:insert into ... value( employee_seq.nextval....);
参数处理
单个参数:Mybatis不做任何处理, 使用 #{参数名},获取参数值,
多个参数:Mybatis多个参数会被封装成一个Map, key:param1 ...paramN, value:是传入的参数值, #{} 从Map中获取指定的key,
#{param1...N} ,对于参数过多,则不好使用,使用命名参数,
<select id="getEmployees" resultType="com.dong.service.employee">
select * from BLog where id = #{param1} and id2 = #{param2}
</select>
命名参数:明确指定封装参数时Map的key:@Param("id")
key:为使用@Param注解的值
value:为参数值
public employee getEmployees(@Param("id")Integer id,@Param("id2")Integer id2);
#{指定的命名值}
<select id="getEmployees" resultType="com.dong.service.employee">
select * from BLog where id = #{id} and id2 = #{id2}
</select>
POJO
如果多个参数正好是Bean,则可以直接传递POJO, #{属性名} 即可获取pojo的值,
如果多个参数不是业务逻辑的模型,没有对应的POJO,则可以传入Map,
#{key} : 取出Map对应的值,
如果多个参数不是对应的Bean,但经常使用,则推荐使用一个(transfer object) 传输对象,
特别注意,如果Collection(list, Set)类型或者数组,也会特殊处理,把传入的list或者数组封装在Map中,
Key: 为collection
如果是List,可使用key:list eg: #{list[0]}
如果是Array,可使用key:array
<insert id="addEmployee" parameterType="com.dong.service.employee" useGeneratedKeys="true" keyProperty="id">
insert into tbl_employee(last_name,email,gendar) values (#{list[0]},#{list[1]},#{list[2]})
</insert>
参数值的获取
#{}:获取Map中的值或者POJO对象属性的值,
${}:获取Map中的值或POJO对象属性的值,
区别: #{}是以预编译的形式,将参数设置到SQL语句,使用占位符
${}取出值直接封装在SQL语句中,存在安全问题.
大多数情况下,我们取参数的值都应该使用 # { } ,在不支持占位符的地方我们可以使用${}方式.
#{}更丰富的用法:
规定参数的一些规则:
JavaType,jdbcType,mode,numericScale,resultMap,typeHandler,jdbcTypeName,expression.
jdbcType:当数据为null时,有些数据库不能识别mybatis对null的默认处理,eg:Oracle,
mybatis将 null类型映射为数据库类型的 OTHER类型,对于Oracle是不认识,而对MySQL可以识别.可以进行制定:eg: #{email,jdbcType=NULL}
由于全局配置中的jdbcTypeForNull=OTHER,oracle不支持, 所以可以在#{}中修改,也可以修改全局配置,
Select
Select: 普通的参数不做介绍,
当返回值为List时,在写映射时,resultType的类型为List中元素的类型,
当返回类型Map时,返回一条记录的Map,,key为列名,值为对应的值,在写映射时,resultType的类型为Map,
当返回类型Map时,返回多条记录封装成一个Map,Map<String,Employee>:键是主键,值为封装后的Javabean,
写映射时,resultType的类型为集合中元素的类型,如果想要指定key使用哪个属性,则需要在方法上使用@MapKey("")
resultMap:自定义结果集映射规则,resultMap 和 resultType只能二选一,
type:自定义Java类型, id:唯一id,方便引用,
<resultMap type="", id ="" >
id: 指定主键的封装规则,column:指定列, property:指定对应的JavaBean属性,
<id column="" ,property=""/>
指定普通列封装的规则,
<result column="" ,property=""/>
其他不指定的列会自动封装,尽量写出所有列的对应,
</resultMap>
<resultMap type="com.dong.service.employee" id="test">
<id column="id" property="id"/>
<result column="name" property="name"/>
</resultMap>
然后再select中使用resultMap引用定义好的映射规则即可.
<select id="getEmployee" resultMap="test" resultType="com.dong.service.employee" databaseId="mysql" >
select * from Blog where id = #{id}
</select>
联合查询,级联属性封装结果,对于别的表的属性,则使用属性.属性即可.还可以使用:<association>可以指定联合的JavaBean对象,eg:
proeorty:指定哪个对象是联合属性, JavaType:指定属性对象的类型,然后再assocaition的标签内定义映射规则,
<association property="dept" JavaType="com.dong.department">
<id.../>
<result .../>
</association>
association分步查询
select:表明当前属性是调用select指定的方法查出的结果
column:指定将哪一列的值传递给这个方法
流程:首先使用select指定方法(传入column指定的这列参数的值,)查出对象,并封装给property指定的属性,
如果想要在使用的时候才进行加载,则可以使用懒加载机制,可在setting中进行设置.
如果关联多个对象:集合
即查询部分是,将对应部分的所有员工信息也查询出来:
collection定义关联集合类型的属性的封装,
property:对应的属性名 ofType:指定集合列元素的类型
<collection property= "" ofType="com.dong.xxxbaen">
定义这个集合中的元素的封装规则,
<id column="xx" property="xx" />
<result column="xx" property="xx" />
......
</collection>
<resultMap type="com.dong.service.employee" id="test">
<id column="id" property="id"/>
<result column="name" property="name"/>
<!-- association 是关联一个对象,如果是多个对象,则使用collection -->
<!-- property为对应的多个对象的属性,select为另一个查询,其值为另一个查询的id标识,column为使用哪个id进行查询 -->
<collection property="emp"
select="funciont_id" column="id" fetchType="lazy"></collection>
</resultMap>
注:如何在collection的 select 语句中传入多个column值,可以将多列值封装到Map中传递, column= “{key1 = column1,key2 = column2} fetchType:设置加载,可选延迟加载,立即加载,
discriminator
resultMap中的 discriminator 鉴别器,,用来判断某列的值,然后根据某列的值改变封装行为,
JavaType:列值对应的Java类型, column:指定判定的列名,
<discriminator JavaType="string" column="gender">
<case value = " " resultType="xxx">
相应的规则
</case>
<case value= " " resultType="xxx">
相应的规则,
</case>
</discriminator>
如有异议,敬请指出,谢谢观看,与君共勉.(观看https://www.bilibili.com/video/av45816095?t=113&p=36)