1、由于是入门级demo,所以直接弄个java工程,也不用maven了
先来看工程的目录结构
这里学习下
java中build path是什么?
如果你只是将jar包复制到Java工程里面去,那么是无法使用到jar包里面的类,因为编程ide无法找到jar包。所以build path其实就是添加jar包的路径,让ide可以找到这个路径对应的jar包的文件,从而来能够使用jar包中的方法。
2、实体类
@Data
public class Employee {
private Integer id;
private String lastName;
private String email;
private String gender;
}
3、mybatis的全局配置文件
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/mybatis" />
<property name="username" value="root" />
<property name="password" value="houchen" />
dataSource>
environment>
environments>
<mappers>
<mapper resource="EmployeeMapper.xml" />
mappers>
configuration>
4、sql映射文件 + mapper接口
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.mybatis.mapper.EmployeeMapper">
<select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee">
select id,last_name lastName,email,gender from tbl_employee where id = #{id}
select>
mapper>
public interface EmployeeMapper {
public Employee getEmpById(int id);
}
5、测试代码
/*
1、sqlSession代表和数据库的一次会话,用完必须关闭
2、SqlSession是非线程安全的,每次使用都应该创建一个新的对象
3、mapper接口没有实现类,但是mybatis会为这个接口生成一个代理对象
4、两个重要的配置文件:
mybatis的全局配置文件
sql映射文件
*/
public class MybatisTest {
public SqlSessionFactory getSqlSessionFactory() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
return sqlSessionFactory;
}
/*
* 1、根据xml配置文件(mybatis的全局配置文件)创建一个SqlSessionFactory对象
* 2、sql映射文件
* 3、将sql映射文件注册到mybatis全局配置文件
*/
@Test
public void test() throws IOException {
SqlSession openSession = getSqlSessionFactory().openSession();
try {
Employee employee = openSession.selectOne(
"com.atguigu.mybatis.dao.EmployeeMapper.getEmpById", 1);
System.out.println(employee);
} finally {
openSession.close();
}
}
@Test
public void testMapper() throws IOException {
SqlSession openSession = getSqlSessionFactory().openSession();
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
Employee e = mapper.getEmpById(1);
System.out.println(e);
}
}
mybatis可以使用properties来引入外部properties配置文件的内容
这是mybatis中极为重要的调整设置,他们会改变mybatis的运行时行为
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
settings>
<typeAliases>
<package name="com.atguigu.mybatis.bean"/>
typeAliases>
<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>
<databaseIdProvider type="DB_VENDOR">
<property name="MySQL" value="mysql"/> //支持mysql环境
<property name="Oracle" value="oracle"/> //支持oracle环境
databaseIdProvider>
databaseId:告诉mybatis 这条语句是在什么环境下执行的
<select id="getEmpById" resultType="employee" databaseId="mysql">
select id,last_name,email,gender from tbl_employee where id = #{id}
select>
<mappers>
<package name="com.atguigu.mybatis.mapper"/>
mappers>
<insert id="addEmp" parameterType="com.atguigu.mybatis.bean.Employee" useGeneratedKeys="true"
keyProperty="id">
insert into tbl_employee(last_name,email,gender)
values(#{lastName},#{email},#{gender})
insert>
<insert id="addEmp" databaseId="oracle">
/*
keyProperty: 查出的主键值封装到javaBean的哪个属性
order = "BEFORE" 当前sql在插入sql之前运行
"AFTER" 当前sql在插入sql之后运行
resultType : 查出的数据的返回值类型
*/
<selectKey keyProperty="id" order="BEFORE" resultType="Integer">
/*编写查询主键的sql语句*/
select employees_seq.nextval from dual;
selectKey>
/*插入的主键是从序列中拿到的*/
insert into employees(id,last_name,email,gender)
values(#{lastName},#{email},#{gender})
insert>
单个参数
mybatis不会做特殊处理,#{参数名} 取出参数
多个参数
mybatis会做特殊处理,多个参数会被封装成一个map,
key:param1…paramN
value: 对应的按照顺序传入的参数
#{param1} 就是从map中获取指定的值
命名参数(@param(“xxx”))
明确指定封装参数时map的key ==》接口定义时,使用@param注解
多个参数会被封装成一个map
key:使用@param注解指定的值
value:参数值
#{key} 就是从map中获取指定的值
public Employee getEmpByIdAndLastName(@Param("id") int id, @Param("lastName") String lastName);
<select id="getEmpByIdAndLastName" resultType="employee">
select id,last_name,email,gender from tbl_employee
where id = #{id} and last_name =#{lastName}
</select>
实体类
如果多个参数正好是我们业务逻辑的数据原型,可以之间传入pojo;#{属性名} 取出对应的值
Map
如果多个参数不是业务模型中的数据,没有对应的pojo,为了方便,我们也可以传入map
#{key} 取出对应的值
【补充】
参数值的获取
#{} :以预编译的形式,将参数设置到sql语句中,类似于jdbc的参数占位符,防止sql注入
${} : 取出的值直接拼装在sql语句中,会有安全问题
如果select返回list ,resultType 取得是 list 中的泛型
如果select返回map,resultType = “map”
<resultMap id="myemp" type="com.atguigu.mybatis.bean.Employee">
<id column="id" property="id">id>
<result column="last_name" property="lastName">result>
resultMap>
<select id="getEmpById" resultMap="myemp">
select * from tbl_employee where id = #{id}
select>
<resultMap id="myEmpDept" type="com.atguigu.mybatis.bean.Employee">
<id column="id" property="id">id>
<result column="last_name" property="lastName">result>
<result column="gender" property="gender">result>
<result column="email" property="email">result>
<result column="did" property="dept.id">result>
<result column="dept_name" property="dept.deptName">result>
resultMap>
<select id="getEmpAndDept" resultMap="myEmpDept">
select
e.id id,
e.last_name last_name,
e.gender gender,
e.email email,
d.id did,
d.dept_name dept_name
from tbl_employee e left join tbl_dept d
on e.dept_id = d.id
where e.dept_Id = 2
select>
<resultMap id="myEmpDept1" type="com.atguigu.mybatis.bean.Employee">
<id column="id" property="id">id>
<result column="last_name" property="lastName">result>
<result column="gender" property="gender">result>
<result column="email" property="email">result>
<association property="dept" javaType="com.atguigu.mybatis.bean.Department">
<result column="did" property="id">result>
<result column="dept_name" property="deptName">result>
association>
resultMap>
<select id="getEmpAndDept" resultMap="myEmpDept1">
select
e.id id,
e.last_name last_name,
e.gender gender,
e.email email,
d.id did,
d.dept_name dept_name
from tbl_employee e left join tbl_dept d
on e.dept_id = d.id
where e.dept_Id = #{id}
select>
先准备好department对象的mapper和 xml文件
DepartmentMapper.xml
<select id="getDeptById" resultType="com.atguigu.mybatis.bean.Department">
select id,dept_name deptName from tbl_dept where id =#{id}
select>
EmployeeMapperPlus.xml
<resultMap id="myEmpDept2" type="com.atguigu.mybatis.bean.Employee">
<id column="id" property="id">id>
<result column="last_name" property="lastName">result>
<result column="gender" property="gender">result>
<result column="email" property="email">result>
<association property="dept" select="com.atguigu.mybatis.mapper.DepartmentMapper.getDeptById" column="dept_id">
association>
resultMap>
<select id="getEmpAndDept" resultMap="myEmpDept2">
select
e.id id,
e.last_name last_name,
e.gender gender,
e.email email,
e.dept_id
from tbl_employee e
where e.dept_Id = #{id}
select>
只有在真正用到关联对象时,才会进行第二次的分布查询
mybatis配置文件中,添加配置
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
settings>
<resultMap id="myDept" type="com.atguigu.mybatis.bean.Department">
<id column="did" property="id">id>
<result column="dept_name" property="deptName">result>
<collection property="emps" ofType="com.atguigu.mybatis.bean.Employee">
<id column="eid" property="id">id>
<result column="last_name" property="lastName">result>
<result column="email" property="email">result>
<result column="gender" property="gender">result>
collection>
resultMap>
<select id="getgetDeptByIdPlus" resultMap="myDept">
select
d.id did,
d.dept_name dept_name,
e.id eid,
e.last_name last_name,
e.email email,
e.gender gender
from tbl_dept d
left join tbl_employee e
on d.id =e.dept_id
where d.id =#{id}
select>
<resultMap id="myDeptStep" type="com.atguigu.mybatis.bean.Department">
<id column="id" property="id">id>
<result column="dept_name" property="deptName">result>
<collection property="emps" select="com.atguigu.mybatis.mapper.EmployeeMapper.getEmpsByDeptId" column="id">
collection>
resultMap>
<select id="getgetDeptByIdStep" resultMap="myDeptStep">
select id,dept_name from tbl_dept where id =#{id}
select>
下图中sql打印了两次,可见确实是分步查询
【扩展】:分步查询select中方法,如果要传多列的值:
将多列的值封装成map传递
column = “{k1= column1}”
fetchType ="lazy":表示延迟加载
-lazy :延迟加载
-eager: 立即查询
<collection property="emps" select="com.atguigu.mybatis.mapper.EmployeeMapper.getEmpsByDeptId" column="id" fetchType="lazy">
collection>
<select id="getEmpsByConditionIf" resultType="com.atguigu.mybatis.bean.Employee">
select * from tbl_employee
where 1=1
<if test="id!=null">
and id = #{id}
if>
<if test="lastName!=null and lastName !=''">
and last_name like '%${lastName}%'
if>
<if test="email!=null">
and email like '%${email}%'
if>
<if test="gender==0 or gender == 1">
and gender = #{gender}
if>
select>
去除动态sql中多余的and 和 or
<select id="getEmpsByConditionIf" resultType="com.atguigu.mybatis.bean.Employee">
select * from tbl_employee
<where>
<if test="id!=null">
and id = #{id}
if>
<if test="lastName!=null and lastName !=''">
and last_name like '%${lastName}%'
if>
<if test="email!=null">
and email like '%${email}%'
if>
<if test="gender==0 or gender == 1">
and gender = #{gender}
if>
where>
select>
<select id="getEmpsByConditionTrim" resultType="com.atguigu.mybatis.bean.Employee">
select * from tbl_employee
<trim prefix="where" suffixOverrides="and">
<if test="id!=null">
id = #{id} and
if>
<if test="lastName!=null and lastName !=''">
last_name like '%${lastName}%' and
if>
<if test="email!=null">
email like '%${email}%' and
if>
<if test="gender==0 or gender == 1">
gender = #{gender} and
if>
trim>
select>
<select id="getEmpsByConditionChoose" resultType="com.atguigu.mybatis.bean.Employee">
select * from tbl_employee
<where>
<choose>
<when test="id!=null">
and id = #{id}
when>
<when test="lastName!=null and lastName !=''">
and last_name like '%${lastName}%'
when>
<otherwise>
and gender = 1
otherwise>
choose>
where>
select>
用来更新数据库中的字段
<update id="updateEmp">
update tbl_employee
<set>
<if test="lastName!=null">
last_name=#{lastName},
if>
<if test="email!=null">
email=#{email},
if>
<if test="gender!=null">
gender=#{gender}
if>
set>
where id=#{id}
<foreach collection="ids" item="item_id" separator=","
open="where id in(" close=")">
#{item_id}
foreach>
select>
mysql foreach 批量保存
<insert id="addEmps">
insert into tbl_employee(last_name,email,gender,dept_id)
values
<foreach collection="emps" item="emp" separator=",">
(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
foreach>
insert>
两个内置参数:
不只是方法传递过来的参数可以被用来判断,取值。。。
mybatis默认还有两个内置参数:
_parameter:代表整个参数
单个参数:_parameter就是这个参数
多个参数:参数会被封装为一个map;_parameter就是代表这个map
_databaseId:如果配置了databaseIdProvider标签。
_databaseId就是代表当前数据库的别名
定义sql片段:
<sql id="sqlColumn">
id,last_name,email,gender
sql>
引用sql片段:
<select id="getEmpsByConditionChoose" resultType="com.atguigu.mybatis.bean.Employee">
select
<include refid="sqlColumn">include>
from tbl_employee
<where>
<choose>
<when test="id!=null">
and id = #{id}
when>
<when test="lastName!=null and lastName !=''">
and last_name like '%${lastName}%'
when>
<otherwise>
and gender = 1
otherwise>
choose>
where>
select>
mybatis包含一个非常强大的查询缓存特性,他可以非常方便的配置和定制,缓存可以极大的提高查询效率
mybatis系统中提供了两级缓存:
@Test
public void testFirstCache() throws IOException {
SqlSession sqlSession = getSqlSessionFactory().openSession();
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
Employee emp = mapper.getEmpById(1);
System.out.println(emp);
Employee emp1 = mapper.getEmpById(1);
System.out.println(emp1);
System.out.println(emp1==emp);
}
【结论】 由上面的结果可以看出
两次查询,但是只打印了一次sql语句,说明第二次查询是从缓存中直接取出的结果,而不是再一次执行查询操作
一级缓存的失效情况(没有使用到当前一级缓存的情况,也就是,还需要向数据库发出查询)
1、sqlSession不同
2、sqlSession相同,但是查询条件不同
3、sqlSession相同,两次查询之间执行了增删改操作(这次操作可能对之前的数据有影响)
4、sqlSession相同,手动清除了一级缓存