和数据库交互,持久化层框架,MyBatis
sql全部写在配置文件。解耦。
*MyBaits底层就是对原生JDBC的一个简单封装。
轻量级框架。
为什么不用原生jdbc?sql语句是硬编码在程序中,数据库层和java编码耦合
(1)导包
日志包也导一下 log4j
依赖类路径 log4j.xml配置文件
(2)
1.创建表
2.创建javabean封装表的数据
3.操作数据库的接口 dao接口
public Employee getEmpById(Integer userId);
//根据员工id查询员工
public Employee getEmpByIdAndName(@Param("userId")Integer userId,@Param("name") String name);
//根据员工id和名字来查询员工
public List<Employee> getAllEmps();
//刚刚是一个员工,如果是所有员工呢,员工的list
@MapKey("id")
public Map<Integer,Object> getAllEmpsReturnMap();
//刚刚是一个员工,如果是所有员工呢,员工的map
//主键:key 对象:value
public Map<String,Object> getEmpByIdReturnMap(Integer userId);
//根据员工id查询员工,返回的是map
//列名:key,列值:value
public int updateEmployee(Employee employee);
public int deleteEmployee(Integer userId);
public int insertEmployee(Integer userId);
(3)mybatis全局配置文件 (mybatis-config)
1.properties resource引入外部数据源配置
这下面是配置数据源dataSource(数据库连接池)的 ${}取外部的值
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
2.settings有很多属性,其中有个属性mapUnderscoreToCamelCase
开启自动驼峰命名规则
有时候可以自定义结果集,把sql语句结果 封装 成javabean对象
这个时候,因为数据库的列名写少了(比如cname)
3.关联对象延迟加载,属性按需加载
4.typeHandlers 类型处理器
比如数据库里面数据类型是varchar 然后javabean里面是string
Mybatis四大对象
执行器Executor 负责执行sql语句//
参数处理器 调用typeHandlers 类型处理器
结果集处理器 把sql语句结果封装成javabean对象
处理器
4.environment 配置具体的环境 必备:1.数据源 2.事务切面类
(后来spring来做)
测试人员的数据源呀 另一个服务器的数据源
5.从mybatis全局配置文件中可以构建sqlSessionFactory
(4)dao接口不是有很多操作数据库的方法吗
如何向数据库发送sql语句????
》》写这个dao接口的配置文件,相当于实现类。
namespace:名称空间,告诉mybaits,配置文件实现哪个Dao接口
<mapper namespace="com.at.dao.EmployeeDao">
select:定义一个查询操作,
id:方法名。因为这个配置是对于某个方法的实现!!!!!
resultType:方法返回值类型,默认规则
如果是集合(list,map),就返回集合中元素的类型 ,
返回单条记录的map的话就是map
resultMap:自定义结果集
增删改不用写返回值类型,返回影响多少行
让mybatis自动的将自增id 赋值给 传入对象的id属性
useGeneratedKeys="ture"
keyProperty=将刚刚自增的id封装给哪个属性
<select id="getEmpById" resultType="com.at.bean.Employee">
select * from employee where id = #{id}
</select>
<update id="updateEmployee">
update employee
set name=#{name},gender=#{gender},email=#{email}
where userId = #{userId}
</update>
<delete id="deleteEmployee">delete from employee
where userId = #{userId}</delete>
<insert id="insertEmployee" useGeneratedKeys="true" keyProperty="userId">
insert into employee(name,gender,email)
values(#{name},#{gender},#{email})
</insert>
<select id="getAllEmps" resultType="com.at.bean.Employee">
select * from employee where id = #{id}
</select>
<select id="getEmpByIdReturnMap" resultType="map">
select * from employee where id = #{id}
</select>
<select id="getAllEmpsReturnMap" resultType="com.at.bean.Employee">
select * from employee where id = #{id}
</select>
传参现象:
单参:
基本类型 #{随便写}
pojo:#{随便写}
多参:
#{}失效
除非0,1用这个参数的索引,或者param1,param2
原因:如果是传入了多个参数,mybatis会把多参封装到map中
所以取值要用map中的key(1,2。。。)
解决: 所以我们可以在方法的参数前加个@Param标签
指定封装到map中的key
为什么要写#{},参数的位置都是用?代替,参数是后来预编译设置进去的
如果写${},不是参数预编译,而是直接和sql语句进行拼串。
自定义结果集,自己定义每一列数据和javaBean的映射规则。
应用情况:
关联查询(join查询)用它没错,你查出来的列值对应哪一个表,
分步查询可以,关联对象延迟加载,属性按需加载。在全局配置文件中。但是和数据库连接两次
解决方案:
1-1关联 javaBean对象有一个javaBean对象
- 级联属性封装结果 property=对象名.属性
- association标签 property=对象名 javatype=对象所在的类名
- association标签可以分步查询 不写 javatype,写这个指定的sql ,用select=xxx (xxx为namespace.id),让mybatis调用指定的sql column=分布查询是哪一列的值
分步查询会造成严重性能的浪费,发了两个sql,结果只用到第一个sql。
所以分步查询可以,所有关联对象延迟加载,属性按需加载。在全局配置文件中,但是和数据库连接两次
1-n关联:外键在n表 javaBean对象有一个集合对象 List
- collection标签 property=集合对象 ofType=集合元素的类名
n-n 关联: 有中间表
resultmap:自定义结果集
type:为哪一个javaBean定义映射规则
id column:指定主键列 (数据库)
property:javaBean的哪个属性
result column:指定普通列 (数据库)
property:javaBean的哪个属性
<resultMap type="",id="">
<id column="" property="" />
<result column="" property="" />
</resultMap>
级联属性封装结果:
两个表如果都有id,取别名: l.id 别名
association标签
分布查询
1-n
记得遍历List for循环
动态sql=sql语句动态拼串
应用场景:
1. Dao接口里面 select方法。如果你只是想根据传入对象的部分属性去查询
where=取出前面多余的and
trim: prefix=为整体sql加个where,prefixOverrides=取出前面多余的and
<if test>
<choose> <when test> <otherwise>
test:指定javabean属性的判断条件
xml文件中写这些 ><&&判断符,有些要写成转义符
<select id ="getTeacherByCondition" resultMap="teacherMap">
select * from t_teacher
<trim prefix="where" prefixOverrides="and" >
<if test="id!=null">
and id > #{id}
</if>
<if test="name!=null and name!="" ">
and teacherName like #{name}
</if>
<if test="birth!=null">
and birth_date < #{birth}
</if>
</trim>
</select>
where查询后面跟着 in,也就是说你传入了一个集合,
多参封装进map,取值,规定map的key @Param
这个集合有几个对象你不知道,
也就是你这个in后面跟着几个对象你不知道
foreach collection=帮我们遍历集合,iteam=每遍历元素的值,
separator=,
<select id ="getTeacherByIdIn" resultMap="teacherMap">
select * from t_teacher where id in
<foreach collection="ids" iteam="id_item" separator=","
open="(" close=")" >
#{id_item}
</foreach>
</select>
以前的更新是这个对象的全字段更新,太菜了,现在的的更新是部分字段更新
set:取出多余的,
(5)我们写的dao接口的实现文件(mapper文件)
mybatis是默认不知道的,
需要在全局配置文件中注册。
全局配置文件怎么去注册呢? 有个mapper标签
mapper:引入我们自己编写的Dao接口的实现文件
package name:可以批量注册我们的dao接口的实现文件
<mappers>
resource:可以在类路径下找资源
class:直接引入接口全类名,接口和实现文件同包同名
<mapper class="com.at.bean.EmployeeDao"/>
<mapper resource="EmployeeDao.xml"/>
</mappers>
(6)
每个基于mybatis的应用,都是以一个SqlSessionFactory的实例为中心
1.根据全局配置文件 创建一个SqlSessionFactory
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream =Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory =new SqlSessionFactoryBuilder().build(inputStream);
2.获取数据库的一次会话 SqlSessionFactory.openSession(true)
底层就是获取到了数据库的连接。
SqlSessionFactory:创建SqlSession对象(一个)
true:获取到的连接自动提交
一个SqlSession代表的就是和数据库的一次会话。
sqlSession对象,多线程不共享他,要操作就拿一个新的,
也就是不放在类下。
SqlSession openSession = SqlSessionFactory.openSession(true);
3.SqlSession对象有个getmapper方法,
EmployeeDao mapper=openSession.getMapper(EmployeeDao.class);
int i =mapper.insertEmployee(new Employee(null,"lala","lalal@qq.com","女"));
没有给这个Dao接口写实现类,
Mybatis自动为这个Dao接口创建动态代理对象
class com.sun.proxy.$Proxy5
问题:
在ssm框架中,常用的日志输出为Log4j,
但按照常规的配置,涉及mybatis那部分日志不能打印出来的;