Mybatis
MyBatis : 是一个持久层的框架, 也就是和数据库进行交互的工具
以往对 数据库的操作是
JDBC -> Dbutils(QuaryRunner) -> jdbcTemplate: 工具
编写sql -> 预编译 -> 设置参数 -> 执行sql -> 封装结果
- 功能简单: sql 语句编写在Java代码里面; 硬编码高耦合的方式。(一旦对某个位置的代码进行修改需要将整个项目重新进行编译、封装、执行 会非常麻烦
Hibernate: 全自动ORM(object Relation Mapping) 框架
该框架旨在消除sql,也就是说无需程序员进行编写sql, 只需要告诉执行目的,由框架来进行sql的编写。 虽然这样看似简化了操作,但是由框架编写的sql是没有办法进行优化的。优化的话,需要学习Hql 无疑是家中了学习负担
javaBean – 编写sql -> 预编译 -> 设置参数 -> 执行sql -> 封装结果 – DbRecords
(最终希望: sql语句交给我们开发人员编写,sql不失去灵活性)
Mybatis 相比于上面两种方式它将sql 的编写放到配置文件中去
MyBatis的helloworld
1、加载SqlSessionFactory
通过全局配置文件mybatis-config.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="${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>
然后通过io流读取xml文件,加载SqlSessionFactory
String resource = "org/mybatis/example/mybatis-config.xml";
// 这里是 mybatis-config的地址
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(inputStream);
2、 采用接口式编程 ,从接口映射到相应的xml文件,在映射到相应的方法。
优点: 无需程序员进行每个接口的实现类的编写,只需要在建立相应的从接口到xml文件的联系即可,无论是在编程上,还是后期维护都更加方便,具有目的性
如下示例
在完成数据库的信息完善后,编写相应的实体类
package bean;
public class Employee {
private Integer id;
private String lastname;
private String email;
private String genter;
// 在这里为了节省篇幅,省略了setter 和 getter 但不代表没有
@Override
public String toString() {
return "Employee [id=" + id + ", lastname=" + lastname + ", email=" + email + ", genter=" + genter + "]";
}
}
接口编写
package dao;
import bean.Employee;
public interface EmployeeMapper {
public Employee getEmpById(Integer id);
}
接口映射的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="dao.EmployeeMapper">
<!--
实现 从接口 到xml文件的映射所需要的
namespace: 但是现在指定为接口的全类名(即从包名到类名),实现从接口到 xml文件的一个映射
id: 唯一标识; 接口中相应方法的名
result: 返回值类型
#{id} : 从传递过来的参数中取出id值
-->
<select id="getEmpById" resultType="bean.Employee">
select * from tbl_employee where id = #{id}
</select>
</mapper>
最终测试方法 以及mybatis-config.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"> <!--xml文件的dtd约束文件 规定xml的于法规定 -->
<configuration>
<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>
<!-- 重要 -->
<mappers>
<mapper resource="EmployeeMapper.xml"/> <!-- -->
</mappers>
<!--
将我们写好的sql映射文件一定要注册到全局映射文件中
映射文件为 EmployeeMapper.xml 全局映射文件为 (mybatis-config.xml)
-->
</configuration>
/**
* 接口式编程
* Dao ==> DaoImpl 这是原生方式
* mybatis Mapper ====> 学习Mapper (这里的Mapper就是对象的实现)
*
*
* 2. SqlSession 对象代表和数据库的一次会话 用完必须关闭
* 3. SqlSession 和connection 一样都是非线程安全的 在多线程环境下会存在资源竞争
* 每次使用都应该去获取新的对象
* 4. 虽然mapper接口没有实现类 但是mybatis接口会为这个接口生成一个代理对象
* 5. 两个重要的配置文件
* 一个是mybatis的全局配置文件, 包含数据库连接池信息 ,事务管理信息等 系统运行环境信息
* sql映射文件,保存了每一个sql的语句的映射信息
* 将sql 抽取出来
*
* @throws IOException
*/
@Test
public void test01() throws IOException {
String resourse = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resourse);
SqlSessionFactory sqlSessionFectory =
new SqlSessionFactoryBuilder().build(inputStream);
SqlSession openSqlSession = sqlSessionFectory.openSession();
EmployeeMapper mapper = openSqlSession.getMapper(EmployeeMapper.class);
/* 我们在这里并没有写实现类,但是文件没有报错,并且也查询到了相应的资源
* 因为在执行getMapper方法后MyBatis会自动创建一个代理对象 代理对象去执行增删改查
*
*/
Employee emp = mapper.getEmpById(1);
System.out.println(emp);
openSqlSession.close();
}
全局配置文件的各个变量
properties
<!--
mybatis 可以使用properties 标签引入外部杯properties指定的内容
两个属性 resource 和 url
resource用于引入类路径下的资源
url用于引入网络路径、磁盘路径
比如引入一个dbconfig.properties 作为数据库的一个信息资源
-->
<properties resource="dbconfig.properties"></properties>
settings
<!--
settings 用来加载xml文件的设置项
在其中使用 setting来进行相应设置项的设置 其中有两个属性 name 对应设置项名 value 相应设置状态。
例如 常用的将Java的驼峰命名法和数据库的下划线命名法进行对应
-->
<settings>
<setting name="mapUnderscoreToCamelCase" value="True"></setting>
</settings>
typeAliases : 设置别名
方式一
<!--
直接指明对应的类名和别名 typeAlias
有两个属性 type 和 value 分别对应类的全名 和 相应的别名
如果没有指定相应的别名 那么默认为类名的小写 在这里就是 employee
-->
<typeAliases>
<typeAlias type="bean.Employee" value="eee"></typeAlias>
</typeAliases>
方式二
<!--
批量别名 只有一个属性 对应包的包名 将会给整个包里的类包括其子包内的类起别名 默认为其类名的小写 如果出现了 母包和子包的类名冲突 那么可以使用注解 举例如下
-->
<typeAliases>
<typeAlias name="bean"></typeAlias>
</typeAliases>
package bean;
import org.apache.ibatis.type.Alias;
@Alias("emp") // 在此处注解 里面写上用于区分的类名
public class Employee{
}
environments、transactionManager、datasource
<!--
environment : 配置一个具体的环境信息, 必须有两个标签 transactionManager dataSource
用来配置环境, 并且可以使用多个transactionManager 和 DataSource 配置多个环境 , default 指定当前使用的 id 代表当前环境的唯一标识
transactionManager
type: 事务管理器的类型 "JDBC" 是JdbcTranscationFactory| MANAGED() ManagedTranscationFactory 在这里使用的MANAGED 是别名
自定义事务管理器 : 需要实现相应的事务管理器的接口 type 就是我们实现的事务管理器的全类名
dataSource
type : UNPOOLED|POOLED|JNDI 分别是不使用数据库连接池 | 使用数据库连接池 | 使用JNDI 技术 这里这些都是别名
-->
<!-- 配置多个environment 当default= 对应id 应用对应的配置环境-->
<environments default="A">
<environment id="A">
<transcationManager type="JDBC">
<dataSource>
<propertity name="dirver" value="${jdbc.driver}"></propertity>
<propertity name="url" value="${jdbc.url}"></propertity>
<propertity name="user" value="${jdbc.user}"></propertity>
<propertity name="password" value="$jdbc.password"></propertity>
</dataSource>
</transcationManager>
</environment>
<environment id="B">
<transcationManager>
<transcationManager type="Manager">
<dataSource>
</dataSource>
</transcationManager>
</transcationManager>
</environment>
</environments>
databaseldProvider
Mybatis 在移植性方面的应用 : 告诉myBatis 写的sql语句是哪个数据库厂商下的,那么就可以根据不同数据库厂商发送相应的sql语句;比如:
<!-- type = "DN_VENDOR" type作用得到相应数据库厂商的标识 这样一来mybatis就可以 根据标识来执行不同的sql 标识有 MYSQL Orace , SQL Sever, 等等等等-->
<databaseIdProvider type="DB_VENDER">
<property name="MYSQL" value="mysql"></property> <!-- 给相应的数据库起别名-->
<property name-"Oracle" value="oracle"></property>
</databaseIdProvider>
在相应的映射文件的映射方法里写明写的是那个数据库语言 例如:
<select id="getEmpById" resultType="bean.Employee" databaseId="mysql"><!-- 指明这里写的是mysql的sql语句-->
select * from tbl_employee where id = #{id}
</select
Mappers
注册SQL映射
<mapppers>
<!--
mapper: 注册一个sql映射
resource: 引用类路径下的sql映射文件
url : 引用网络路径下的 或者 磁盘路径下的映射文件按
class : 引用接口,
注册接口
1.有sql迎合文件,映射文件名碧血和接口文件名一样,并且放在与口同一目录下
2. 没有sql映射文件,所有sql都是利用注解写在接口上的
推荐: 一些重要的,简单的,我们用dao接口来写,一些不重要的 ,为了方便起见我们使用注解来写
-->
<mapper resource="EmployeeMapper.xml"></mapper>
<mapper class="dao.EmployeeMapperAnnotation"></mapper> 这里的class里面填的就是下面文件的全名地址
</mapppers>
// 使用注解添加相应的sql而不是映射文件
package dao;
import org.apache.ibatis.annotations.Select;
import bean.Employee;
public interface EmployeeMapperAnnotation {
@Select("select * from tbl_employee where id=#{id} ")
public Employee getEmpId(Integer id);
}
Mybatis 参数处理
单个参数
mybatis不会做任何特殊处理 #{任何参数名} : 取出参数值
多个参数
多个参数会被封装成一个map,
key: param1,param2…paramN, 或者索引也可以
value: 传入的参数值
#{就是从map中获取指定的key的值}
异常:
org.apach.ibatis.binding.bingingExcepting:
Parameter ‘id’ not found.
Available parameters are [1,0,param1,param2]
操作:
//方法:
pubic employee getEmpByIdAndLastName(Integer id, String lastName)
// 取值:
#{id},#{listName}
//SQL
// SELECT * from tbl_employee where id=#{param1} and lastName=#{param2}
命名参数
明确封装参数是param 的 key 和 value
pubic employee getEmpByIdAndLastName(@Param("id")Integer id, @Param("lastName")String lastName)
//SQL
// SELECT * from tbl_employee where id=#{id} and lastName=#{lastName}
pojo
如果多个参数正好是我们多个业务逻辑的数据莫名,我们就jiuzhijei 传入pojo 传#{属性名}
map
如果多个参数不是业务模型中的数据,没有对应的pojo,为了方便 我们注解传入一个map
} pubic employee getEmpByIdAndLastName(Map<K,T> map)
TO
如果多个参数不是业务模型中的数据,但是经常要使用,推荐来编写一个TO(Transfer Object)
Page{
int index;
int size;
}