Mybatis:和数据库进行交互,持久层框架
工具:一些功能的简单封装
框架: 某个领域的整体解决方案;
不用原生的jdbc:
1)麻烦
- sql语句是硬编码在程序中;耦合 (数据库和java编码耦合)
库交互的框架(Hibernate--数据orm框架)
缺点: 定制sql HQL(Hibernate自己的sql语言) 全映射 ; 部分字段映射很难;假设有1000个字段会全部帮你映射上,大大的降低了数据库的性能
orm:对象关系映射(Object Relational Mapping,简称ORM)
- Mybatis将重要的步骤抽取出来可以人工定制,其他步骤自动化.学习mysql只要学习如何写sql不需要关注其他的
- 重要步骤都是写在配置文件中(好维护)
- 完全解决了数据库的优化问题;
- Mybatis底层就是对原生JDBC的一个简单封装
- 即将java编码与sql抽取出来,还不会失去自动化的功能;半自动的框架.
mybatis的两个文件:
- mybatis-config.xml: mybatis的全局配置文件;指导mybatis正确运行的一些全局配置
- sql映射文件: EmployeeDao.xml 相当于对于一个dao接口的实现描述
细节:
-
通过 session.getMapper(xx.class) 获取到的是接口的代理对象,有mybatis自动创建的
-
SqlSessionFactory 和SqlSession
- SqlSessionFactory 是帮助我们创建sqlSession对象 只需要new一次就行了
- sqlSession是我们和数据库的一次会话 ,相当于Connection,一次会话就应该创建一个对象,在会话结束应该有关闭
<?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">
<!--dtd 当前配置文件的约束文件-->
<configuration>
<properties resource="jdbc.properties"></properties>
<!--日志的配置信息-->
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
<typeAliases>
<typeAlias type="com.hy.dao.EmployeeDao" alias="emp"></typeAlias>
</typeAliases>
<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="${jdbc.name}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!-- 引入我们自己编写的每一个接口的实现文件 -->
<mappers>
<mapper resource="com/hy/dao/EmployeeDao.xml"/>
</mappers>
</configuration>
全局配置文件
mybatis-config.xml
- 引入外部配置文件
<!-- 和spring中的 context:property-placeholder一样; 引用外部配置文件 -->
<properties resource="jdbc.properties"></properties>
</configuration>
- settings
<!--为mybatis配置日志-->
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
一个配置完整的 settings 元素的示例如下:
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="useGeneratedKeys" value="false"/>
<setting name="autoMappingBehavior" value="PARTIAL"/>
<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25"/>
<setting name="defaultFetchSize" value="100"/>
<setting name="safeRowBoundsEnabled" value="false"/>
<setting name="mapUnderscoreToCamelCase" value="false"/>
<setting name="localCacheScope" value="SESSION"/>
<setting name="jdbcTypeForNull" value="OTHER"/>
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>
设置别名
<typeAliases>
<typeAlias type="com.hy.dao.EmployeeDao" alias="emp"></typeAlias>
<!-- 采用package的方式 mybatis会为包下(后代包)的每一个实体类起一个别名 默认为类名全小写 @Alias("emp")可以为指定的类起别名 -->
<package name="com.hy.dao"/>
</typeAliases>
- 引入我们自己编写的每一个接口的实现文件
<!-- 引入我们自己编写的每一个接口的实现文件 -->
<mappers>
<!-- resource 在类路径下找接口的xml配置文件
url: 写磁盘的路径
class: 接口的全类名 需要将xml和接口放在同目录下,而且文件名和接口名一致
<mapper resource="com/hy/dao/EmployeeDao.xml"/>
-->
<!--批量注册 name : dao所在的包名
如果没有使用注解的方式,mybatis如何知道我们的接口对应哪个配置文佳的?
要求dao接口和配置文件在一个包下 (可以在类路径下创建一个和dao名称一样的文件夹 在编译的时候可以合并)
-->
<package name="com.hy.dao"/>
</mappers>
mapper.xml 中获取插入后的自增id
<!--抽取公共的sql-->
<sql id="select * from employee"/>
<!--增删改不用写返回值类型-->
<!--获取插入后自增的id
useGeneratedKeys : true 使用原生JDBC获取自动增长的id的方法
keyProperty : 将刚才自增的id封装给那个属性
-->
<insert id="saveEmployee" useGeneratedKeys="true" keyProperty="id">
/*在核心sql文件执行之前 查询sql拿到id 之后赋值给 keyProperty 的字段*/
<selectKey order="BEFORE" keyProperty="id">
select max(id) from employee
</selectKey>
insert into employee values(default ,#{empname},#{gender},#{email})
</insert>
- mybatis中 方法的参数问题
1) 单个参数
基本类型 :
取值: #{随便写}
传入pojo
2)多个参数:
Employee getEmpByIdAndName(Integer id, String name);
取值: #{参数名} 无效了
可用: 0 ,1 参数的索引 或者 param1 ,param2 (第几个参数paramN)
原因:只要传入了多个参数, mybatis会自动将这些参数封装在一个map中;
封装时使用的key就是参数的索引和参数的第几个表示
Map<String,Object> map = new HashMap<>();
map.put("1",传入的值);
map.put("2",传入的值)
#{key}的方式就是从这个map中取值 所以可以拿到值
解决方法
Employee getEmpByIdAndName(@Param(value = "id") Integer id,@Param(value = "empname") String name);
告诉mybatis在封装参数的时候 按照我们给定的key来封装
3) 传出pojo
#{pojo的属性名}
4)传入map:
手动将需要的参数封装到一个map中, 在sql #{id}中写的id作为map的key,需要传入的值为value
取值:#{key}
扩展
多个参数的情况下mybatis会自动封装成map
method01(@Param("id")Integer id,String empname,Employee employee);
取值:
Integer id ==>#{id}
String empname ==> #{param2}
Employee employee ==> #{param3.email}
mybtis中的sql取值问题
#{xx} : 是参数预编译的方式, 参数的位置都是?代替的,参数都是预编译设置进去的,安全不会有sql注入的问题 select * from employee where id = ${id} and empname=#{empname}
在执行的时候
${XX} 不是参数 预编译,而是直接和sql语句进行拼接的,不安全 会有sql注入的问题
${}的使用场景 : sql语句只有参数位置才能支持预编译,如果我们想要动态的插入表名,就可以使用${}来获取表名
查询返回list问题
resultType=""; 如果返回的是list类型,写的是集合里面的元素的类型
查询单条记录返回map
dao
/**
* 查询单条记录 并且返回一个map
*
* mybatis 会把列名作为key 把 查到的结果作为value 封装到集合中
* @param id
* @return
*/
Map<String,Object> getEmpByIdReturnMap(Integer id);
xml
<select id="getEmpByIdReturnMap" resultType="java.util.Map">
select * from employee where id=#{id}
</select>
查询多个封装成map
dao
/**
* 查询多条记录 将查询到的结果返回给一个map
* key: 这条记录的主键
* value:就是这条记录封装好的对象
* resultType="" 就是value封装的类型
* @return
* @MapKey("id") 把查询出来的值id作为主键
*/
@MapKey("id")
Map<Integer,Employee> getAllEmpReturnMap();
xml
<select id="getAllEmpReturnMap" resultType="com.hy.bean.Employee">
select * from employee
</select>
mybatis自定义封装结果集
1) 按照列名和属性名一一对应的得到规则(不区分大小写)
2)如果不一一对应;
1) 开启驼峰命名发(要满足驼峰命名的规则 aaa_bbb aaa_Bbb)
2) 使用自定义的封装结果集
<mapper namespace="com.hy.dao.CatDao">
<!-- resultMap 使用自定义的规则-->
<select id="getCatByid" resultMap="mycat">
select * from cat where id= #{id}
</select>
<!-- 自定义结果集(resultMap):自己定义每一列数据和javaBean的映射规则
type="" 指定为哪个javaBean指定自定义规则; 全类名
id="" 唯一标识 让别人去引用
-->
<resultMap id="mycat" type="com.hy.bean.Cat">
<!--指定主键的对应规则
column="id" 指定那一列是主键列
property="": 指定cat的那个属性封装id这个属性
-->
<id property="id" column="id"></id>
<!--普通列-->
<result property="age" column="cage"/>
<result property="name" column="cname"/>
<result property="gender" column="cgender"></result>
</resultMap>
</mapper>