Mybatis

2 篇文章 0 订阅

一、什么是mybatis

  1. mybatis是apache组织下的一个开源框架。以前叫ibatis
  2. mybatis是一个持久层的框架解决了orm的问题。
  3. 可以简化jdbc的编码。
    orm:对象关系映射。java是面向对象的语言,数据库是关系型数据库,两者阻抗不匹配。需要有一个中间媒介对两者进行转换。orm映射就是这个中间媒介。orm框架可以将java中的对象转换成数据库表里面的一行数据。也可以将表中的一行数据转换为java中的对象。

二、搭建mybatis的开发环境

在这里插入图片描述
HttpSession是浏览器和tomcat之间的会话,SqlSession是tomcat和数据库之间的会话。

  1. 引入依赖。
  2. 写mybatis的主配置文件
  3. 写入主函数

具体步骤:

  • 引入jar包
<dependency>
    <groupId>com.oracle</groupId>
    <artifactId>ojdbc</artifactId>
    <version>6.0</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.6</version>
</dependency>

提示:ojdbc的jar包由于版权问题,maven的远程仓库里面没有收录该jar包,我们需要在本地仓库里面手动上传。我们提供的本地仓库里面有ojdbc6这个jar包,当我们手动清除本地仓库后,需要专门为ojdbc6复制一份。

  • 写mybatis的主配置文件。(放在resources里面.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="oracle.jdbc.OracleDriver" />
   			<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" />
   			<property name="username" value="hr" />
   			<property name="password" value="hr2" />
   		</dataSource>
   	</environment>
   </environments>
   <!-- <mappers>
   	<mapper resource="org/mybatis/example/BlogMapper.xml" />
   </mappers> -->
</configuration>
  • 写主函数进行测试
public static void main(String[] args) throws IOException {
		//SqlSession
		Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
		SqlSession session = sqlSessionFactory.openSession();
		
		System.out.println(session);
		
		session.close();
	}

三、查询操作

  1. 建表,插入数据。
  2. 创建实体类。
  3. 创建dao 接口。
  4. 在resource里面先创建文件夹。com/baizhi/dao. 注意不能建成com.baizhi.dao .创建好文件夹后,创建一个映射文件。StudentMapper.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">
<!-- namespace为dao接口的全限定名
  指定该映射文件为StudentDao接口服务
-->
<mapper namespace="com.baizhi.dao.StudentDao">
<!-- 
select标签 对应了select操作
id是dao接口中的方法名,resultType是接口的方法的返回值(实体类的全限定名) -->
  <select id="selectOne" resultType="com.baizhi.entity.Student">
  	<!-- 定义该方法要执行的sql语句,其中#{}是占位符,大括号里面的值可以是任意值
  		所以要保证dao接口中的方法的参数的个数是一个。如果是两个的话,需要用其他的方式解决。
  	-->
  	select * from student where id=#{id}
  </select>
</mapper>
  1. 在主配置文件中的对mapper文件进行注册。
<mappers>
    <!-- 告知mybatis有了这个映射文件,注册映射文件 -->
    <mapper resource="com/baizhi/dao/StudentMapper.xml" />
</mappers>
  1. 到主函数里面使用SqlSession对象执行方法。
public static void main(String[] args) throws IOException {
		//将配置文件转换为流对象
		Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
        //创建出SqlSession的工厂类。要把配置文件做为参数传入。
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        //得到session对象。就是数据库的连接
		SqlSession session = sqlSessionFactory.openSession();
		
    	//获取到dao接口的对象。mybatis底层通过java代码动态的产生了一个接口的实现类。getMapper方法就返回了该实现类的对象。
		StudentDao sd = session.getMapper(StudentDao.class);
		Student student = sd.selectOne(41);
		System.out.println(student);
		//释放资源
		session.close();
	}

忘记注册映射文件时报的错误

Type interface com.baizhi.dao.StudentDao is not known to the MapperRegistry.

四、增删改查

  1. 在dao接口定义selectAll方法。
  2. 在映射文件中为selectAll定义sql语句。
<!-- resultType不用定义成集合,需要指定的是sql查询结果映射到哪个类上。mybatis会自动根据查询的条数决定放入到list里面还是一个实体里面。 -->
<select id="selectAll" resultType="com.baizhi.entity.User">
    select * from t_user
</select>

增删改

  1. 在dao接口定义方法。跟以前一样。
  2. 在映射文件中定义标签。
    • 添加的标签是insert
    • 删除的标签是delete
    • 修改的标签是update。

不管是哪个标签id一定是跟dao接口的方法名一致。

<!-- insert标签是用来做插入操作的
  id还是dao的方法名
  -->
<!-- sql语句中的占位符直接写成方法参数(Student对象)的属性(name,age) -->
<insert id="insert">
    insert into student values(stu_seq.nextval,#{name},#{age})
</insert>
  1. 在主函数里面执行完增删改操作后,需要手动提交事务。
//手动提交事务。因为mybatis跟jdbc不一样,不会自动提交事务
session.commit();

特别注意:
mybatis跟jdbc做dml操作时,不一样,不会自动提交事务。需要程序员手动将事务提交。否则控制台不报错,但是表里面没有数据。

五、junt测试

junit是一个测试工具,可以在一个测试类中定义多个测试方法。

package com.baizhi;

import org.junit.Test;

public class TestDao {
    /**
     * 测试方法的返回值一定是void,没有参数
     * 这种测试被称为junit测试。好处一个类中可以定义多个测试方法。
     */
    @Test
    public void testInsert(){
        System.out.println("111");
    }
    @Test
    public void test2(){
        System.out.println("2222");
    }

}

注意事项:

  1. 测试方法上面需要添加@Test注解。
  2. 测试方法的返回值是void,没有参数。

六、dao中多个参数问题

在这里插入图片描述
使用@Param对参数起别名。然后在sql语句中使用#{别名}

七、动态SQL

程序员在写代码代码的时候不能确定sql语句样子,等程序运行的时候才能确定sql的具体内容。
在映射文件中写sql语句的时候我们可以使用mybatis提供的标签实现sql语句的动态变化。

where标签:自动判断sql语句是否需要添加where关键字
if标签:做条件分支。

1. 在xml中小于和大于是特殊字符,需要进行转义。< :&lt; >:&gt;
2. 当使用了动态sql中的if标签,我们的dao方法中的参数必须用@Param起别名。否则if判断里面获取不到参数。

多条件查询

dao层:

public List<Emp> selectAllEmpAndDept(@Param("name")String name,@Param("minAge")Integer minAge,@Param("maxAge")Integer maxAge);

映射文件:

<select id="selectAllEmpAndDept" resultMap="empMap">
    select e.*,d.id did,d.name dname,d.loc loc
    from t_ems_employees e left join t_ems_departments d
    on e.deptid=d.id
    <where>
        <if test="name!=null">
            e.name like '%'||#{name}||'%'
        </if>
        <if test="minAge!=null">
            and e.age &gt; #{minAge}
        </if>
        <if test="maxAge!=null">
            and e.age &lt; #{maxAge}
        </if>
    </where>
</select>

打印sql语句

log4j是一个日志记录工具,可以在控制台上打印出来程序运行的过程。mybatis底层采用了该工具进行了日志打印,如果我们需要在控制上打印出详细的日志信息,需要对mybatis进行如下配置。

  1. 在resources文件夹里面创建配置文件log4j.properties
log4j.rootLogger=ERROR,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} %m%n
log4j.logger.org.springframework=DEBUG
log4j.logger.com.baizhi.dao=DEBUG
  1. 引入依赖
<!--日志记录工具-->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

进过上面的配置之后,项目中就可以打印出真正执行的sql语句。

//表示执行了哪条sql语句
[DEBUG] 2021-04-25 14:37:50,202 ==>  Preparing: select * from train_info WHERE mile > ? and mile < ? 
//执行sql语句时传递的参数
[DEBUG] 2021-04-25 14:37:50,284 ==> Parameters: 600(Integer), 1200(Integer)
//sql语句执行查询出来了几条数据。
[DEBUG] 2021-04-25 14:37:50,362 <==      Total: 6

批量删除

dao:

void deleteMany(@Param("ids") String[] ids);

映射文件:

<delete id="deleteMany">
    delete from train_info where train_no in
    <!--
            collection:表示dao方法的参数是什么类型,数组使用array,list集合使用list.要dao方法只有一个参数,没有注解。
            在dao方法中如果使用了注解,我们需要把collection值配置为注解名字。
            open和close是一组的,表示循环数据前后添加什么字符。
            item:表示每次循环获取到的元素。
            separator:表示元素与元素之间的分割符
         -->
    <foreach collection="ids" open="(" close=")" item="a" separator=",">
        #{a}
    </foreach>
</delete>

八、数据库中字段名和实体类属性名不一致问题

有两种解决办法:

  1. 在执行sql语句的时候直接跟select后面起别名。

  2. 使用resultMap标签指定映射关系。

    第一种:
    在这里插入图片描述
    执行sql的结果跟实体类的属性名已经一致了。这样就会自动的做映射。

    第二种:
    在这里插入图片描述
    这种使用mapper映射的办法是以后的主流方式。

<resultMap type="product" id="proMap">
    <id column="product_id" property="id"/>
    <result column="product_name" property="name"/>
    <result column="price" property="price"/>
    <result column="product_desc" property="desc"/>
</resultMap>
<select id="selectAll" resultMap="proMap">
    select * from t_product
</select>

总结:
在映射文件中的select标签里面什么时候用resultType什么时候用resultMap?

一致时用:resultType
不一致时用:resultMap

九、映射文件中对实体类起别名

<!-- 每次映射文件中使用实体类时都要使用全限定名,很麻烦,我们可以给实体类起别名 -->
<typeAliases>
    <!-- 给Product的类起了别名p,以后在Mapper文件就可以使用p替换全限定名 -->
    <!-- <typeAlias type="com.baizhi.entity.Product" alias="product"/> -->
    <!-- 给包下面所有的类起别名。 类名首字母大小写都可以。 -->	
    <package name="com.baizhi.entity"/>
</typeAliases>

注意这个标签要写在配置数据库连接信息的上面,否则会报错。

整体结构如下:

<?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>
    <typeAliases>
        <!--<typeAlias type="com.baizhi.entity.Train" alias="Train"></typeAlias>-->
        <!--给这个包中所有的类都起别名,别名为类名-->
        <package name="com.baizhi.entity"/>
    </typeAliases>
    <environments default="dev">
        <!--开发的数据库连接信息-->
        <environment id="dev">
            <transactionManager type="JDBC" />
            <!-- 数据库的连接信息 -->
            <dataSource type="POOLED">
                <property name="driver" value="oracle.jdbc.OracleDriver" />
                <property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" />
                <property name="username" value="hr" />
                <property name="password" value="hr" />
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!--<mapper resource="com/baizhi/dao/TrainMapper.xml" />-->
        <!--自动扫描com.baizhi.dao包里面的映射文件。
            要求:dao的接口名要跟映射文件的文件名一致。都叫XxxMapper
        -->
        <package name="com.baizhi.dao"/>
    </mappers>
</configuration>

简化主配置文件中注册映射文件

缺了注册步骤会导致系统报错。mybatis提供了一个标签可以一次性解决该问题。

<mappers>
    <!--<mapper resource="com/baizhi/dao/TrainMapper.xml" />-->
    <!--自动扫描com.baizhi.dao包里面的映射文件。
            要求:dao的接口名要跟映射文件的文件名一致。都叫XxxMapper
        -->
    <package name="com.baizhi.dao"/>
</mappers>

注意事项:要求mapper文件跟dao类名名称一致。

十、 两表联查

左外链接查询=两表中有关联的数据+左表中独立的数据。

右外连接查询=两表中有关联的数据+右表中独立的数据。

内连接查询=两表中有关联的数据。

在多对一查询中我们一般使用左外链接查询。

多对一

步骤:在这里插入图片描述

  1. 建表
--创建部门表
create table t_ems_departments(
    id   number(7) primary key,
    name varchar2(30) not null,
    loc  varchar2(30) not null
);
create sequence ems_departments_seq;
insert into t_ems_departments values(ems_departments_seq.nextval,'技术部','北京');
insert into t_ems_departments values(ems_departments_seq.nextval,'销售部','上海');
insert into t_ems_departments values(ems_departments_seq.nextval,'市场部','郑州');
insert into t_ems_departments values(ems_departments_seq.nextval,'小卖部','广州');

select * from t_ems_departments
--创建员工表
drop table t_ems_employees

create table t_ems_employees(
    id number(7) primary key,
    name varchar2(30) not null,
    salary number(10,2),
    age number(3),
    sex varchar2(10),
    deptid references t_ems_departments(id)   --外键
);
create sequence ems_employees_seq;
insert into t_ems_employees values(ems_employees_seq.nextval,'张三',3000,23,'男',1);
insert into t_ems_employees values(ems_employees_seq.nextval,'叶前伟',13000,23,'男',1);
insert into t_ems_employees values(ems_employees_seq.nextval,'张鹏鹏',10000,23,'男',1);
insert into t_ems_employees values(ems_employees_seq.nextval,'徐通达',14000,23,'男',2);
insert into t_ems_employees values(ems_employees_seq.nextval,'李鹏运',11000,23,'男',3);

  1. 编写查询的sql语句。
	<select id="selectAllEmpAndDept" resultMap="empMap">
		select e.*,d.id did,d.name dname,d.loc loc
			from t_ems_employees e left join t_ems_departments d
			on e.deptid=d.id
	</select>
  1. 创建实体类。在多的一端创建一个属性是一的一端的对象。

public class Emp {
	private int id;
	private String name;
	private double salary;
	private int age;
	private String sex;
	private int deptId;
	private Dept dept;
	....
}
  1. 定义映射关系
	<resultMap type="Emp" id="empMap">
		<id column="id" property="id"/>
		<result column="name" property="name"/>
		<result column="salary" property="salary"/>
		<result column="sex" property="sex"/>
		<result column="age" property="age"/>
		<result column="deptid" property="deptId"/>
		<association property="dept" javaType="Dept">
			<id column="did" property="id"/>
			<result column="dname" property="name"/>
			<result column="loc" property="loc"/>
		</association>
	</resultMap>

一对多

在这里插入图片描述

  1. 实体类的设计,在一的一端写一个属性是list类型的。泛型是多的一端的类型
  2. sql语句的编写。
	<select id="selectAllDeptAndEmps" resultMap="deptMap">
	select d.id did,d.name dname,d.loc,e.*
		from t_ems_departments d left join t_ems_employees e
		on d.id=e.deptid
	</select>
  1. 映射文件
	<resultMap type="Dept" id="deptMap">
		<id column="did" property="id"/>
		<result column="dname" property="name"/>
		<result column="loc" property="loc"/>
		<collection property="empList" ofType="Emp">
			<id column="id" property="id"/>
			<result column="name" property="name"/>
			<result column="salary" property="salary"/>
			<result column="sex" property="sex"/>
			<result column="age" property="age"/>
			<result column="deptid" property="deptId"/>
		</collection>
	</resultMap>

在这里插入图片描述
在这里插入图片描述

十一、 分页插件PageHelper

在这里插入图片描述
步骤:
1.引入jar包

<!--mybatis的分页插件-->
<dependency>
  <groupId>com.github.pagehelper</groupId>
  <artifactId>pagehelper</artifactId>
  <version>5.1.11</version>
</dependency>

2.在mybatis主配置文件mybatis-config.xml中注册该插件。
3.只要在dao里面提供查询所有的方法。
4.调用dao的时候需要两行代码

SqlSession session = MybatisUtil.getSession();
ProductDao pd = session.getMapper(ProductDao.class);
//设置分页信息。第一个参数是页号,第二个参数是一页显示的条数
PageHelper.startPage(1, 3);
//查询全部
List<Product> proList = pd.selectAll();

//把查询全部返回的数据封装到PageInfo对象里面。
PageInfo<Product> pi=new PageInfo<>(proList);

List<Product> list = pi.getList();//获取到当前页的所有数据
pi.getNextPage();//下一页的页号
pi.getPages();//总页数
boolean hasNextPage = pi.isHasNextPage();//是否有下一页
boolean hasPreviousPage = pi.isHasPreviousPage();//是否有上一页
pi.getPageNum();//当前页号


session.close();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值