Mybatis的使用

ORM框架

ORM全称为Object Relational Mapping,关系对象映射,就是将数据表中的一行数据与对象对应起来。

ORM框架提供了持久化类与表的映射关系,运行时把对象持久化到数据库中

Mybatis

Mybatis的前身是iBatis,是一个Java持久层框架。iBatis提供包括了SQL Maps 和 Data Access Objects(DAOs)

Mybatis的使用

在数据库中创建student表

USE mybatis;
//创建student表
CREATE TABLE student
(
    id      INT PRIMARY KEY auto_increment not null,
    name    VARCHAR(255),
    age     INT,
    address VARCHAR(255),
    email   VARCHAR(255)
);
//插入数据
INSERT INTO mybatis.student (id, name, age, address, email) VALUES (1, '张三', 20, '北京', 'zhangsan@example.com');
INSERT INTO mybatis.student (id, name, age, address, email) VALUES (2, '李四', 21, '成都', 'afsdfsd@example.com');
INSERT INTO mybatis.student (id, name, age, address, email) VALUES (3, '王五', 45, '上海', 'safsdfgg@example.com');
INSERT INTO mybatis.student (id, name, age, address, email) VALUES (4, '零六', 23, '杭州', '23fdsgaga@example.com');
INSERT INTO mybatis.student (id, name, age, address, email) VALUES (5, '二狗子', 63, '深圳', 'sdfsdfooo@example.com');

一、创建工程

<!-- Mybatis的包 -->
<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>3.5.13</version>
</dependency>

<!-- JDBC的包 -->
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>8.0.33</version>
</dependency>

二、创建配置文件

在resources目录下创建config.xml

Mybatis支持properties文件的引入,这样做的目的就是为了区分配置:不同的文件中描述不同的配置,这样方便管理。

建立jdbc.properties

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=123456

在config.xml文件中引入

注意:mybatis的配置文件的标签必须按照顺序配置,否则会报错

配置顺序:properties, settings, typeAliases, typeHandlers, objectFactory, objectWrapperFactory, reflectorFactory, plugins, environments, databaseIdProvider, mappers

<?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>
	<properties resource="jdbc.properties"/>
	<typeAliases>
		<!--这里是针对整个包中的类取别名, 别名就是类名,不区分大小写-->
		<package name="cn.cnmd.pojo"/>
	</typeAliases>
    <!--environments代表环境,可以包含多个,比如开发环境、测试环境、生产环境-->
	<environments default="dev">
		<environment id="dev">
            <!--事务管理器,一般默认JDBC-->
			<transactionManager type="JDBC"/>
            <!--数据源,一般默认是POOLED-->
			<dataSource type="POOLED">
				<!--1.3配置连接池需要的参数-->
				<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="mapper/studentMapper.xml"/>
	</mappers>
</configuration>

在resources/mapper目录下创建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">

<mapper namespace="cn.cnmd.mapper.StudentMapper">
    <select id="getStudents" resultType="Student">
		select id, name, age, address, email
		from mybatis.student;
	</select>
</mapper>

三、创建接口/类

在java目录下创建对应的接口cn.cnmd.mapper.StudentMapper

public interface StudentMapper {

	List<Student> getStudents();
}

在java目录下创建表对应的实体类cn.cnmd.pojo.Student

@Data
public class Student {

	private Integer id;
	private String name;
	private Integer age;
	private String address;
	private String email;
}

四、查询

创建一个测试类EasyUseTest

public class EasyUseTest {

	public static void main(String[] args) throws IOException {
		// 获取配置文件
		InputStream in = Resources.getResourceAsStream("config.xml");

		// 创建SqlSessionFactoryBuilder对象
		SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
		// 通过SqlSessionFactoryBuilder对象创建SqlSessionFactory
		SqlSessionFactory factory = builder.build(in);
		// 通过SqlSessionFactory创建SqlSession
		SqlSession session = factory.openSession();

		// 通过SqlSession创建StudentMapper
		StudentMapper mapper = session.getMapper(StudentMapper.class);
		// 通过StudentMapper获取学生列表
		List<Student> students = mapper.getStudents();
		// 遍历学生列表,打印学生信息
		students.forEach(System.out::println);
	}
}

查询结果

Student(id=1, name=张三, age=20, address=北京, email=zhangsan@example.com)
Student(id=2, name=李四, age=21, address=成都, email=afsdfsd@example.com)
Student(id=3, name=王五, age=45, address=上海, email=safsdfgg@example.com)
Student(id=4, name=零六, age=23, address=杭州, email=23fdsgaga@example.com)
Student(id=5, name=二狗子, age=63, address=深圳, email=sdfsdfooo@example.com)

Mybatis配置优化

一、propertise文件配置

在指定数据源时,为了方便管理,Mybatis支持引入properties配置文件

创建包含了连接信息的jdbc.properties配置文件

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=123456

在config.xml中引入并使用

<!--通过peroperties标签引入配置文件-->
<properties resource="jdbc.properties"/>
<!--..........-->
<environments default="dev">
    <environment id="dev">
        <transactionManager type="JDBC"/>
        <dataSource type="POOLED">
            <!--1.3配置连接池需要的参数-->
            <!--使用 ${参数名} 的方式进行赋值-->
            <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>

二、为mapper中的类取别名

在studentMapper.xml文件中,定义一个mapper时,如果时select操作,则需要指定resultType="cn.cnmd.pojo.Student"

<?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="cn.cnmd.mapper.StudentMapper">
    <select id="getStudents" resultType="cn.cnmd.pojo.Student">
		select id, name, age, address, email
		from mybatis.student;
	</select>
</mapper>

为了简化配置,可以在config.xml文件中指定

<typeAliases>
    <!--使用 typeAlias标签 是针对某一个类,别名为alias的值,resultType必须一致-->
    <!--<typeAlias type="cn.cnmd.pojo.Student" alias="stu"/>-->
    <!--使用 package标签 是针对整个包中的类取别名,别名就是类名,不区分大小写-->
    <package name="cn.cnmd.pojo"/>
</typeAliases>

三、日志配置

有时,我们需要看到sql执行的详细内容,就可以配置日志打印

<settings>
    <!-- 打印SQL语句 STDOUT_LOGGING是一个类的别名:
        org.apache.ibatis.logging.stdout.StdOutImpl-->
    <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

Mybatis的增删改查

增删改查都需要在对应的接口中定义对应的增删改查的方法

public interface StudentMapper {

	// 添加学生
	int addStudent(Student student);

	// 删除学生
	int deleteStudent(int id);

	// 更新学生
	int updateStudent(Student student);
    
    //根据id查找某个学生
    Student getStudent(int id);

	// 获取学生列表
	List<Student> getStudents();
}

一、增加(insert)

在stuentMapper.xml文件中定义insert标签,id对应的接口中的方法名,没有返回值类型

没有resultType是因为除了查询,增删改操作的返回结果都是AffectedRows受影响的行数,是整数

参数匹配规则

  1. 如果方法传递的是简单类型参数,比如String、int、long等以及对应的包装类:使用 #{ arg+参数下标 }或者#{ param+参数位置 } 进行占位
select * from student where name = #{ arg0 }and age = #{ arg1 }
select * from student where name = #{ param1 }and age = #{ param2 }
  1. 如果方法传递的是单个对象参数,比如学生类Student:使用 #{ 类的属性名 } 进行占位
insert into student (name, age, address, email) values(#{name}, #{student.age}, #{address}, #{eamil})
  1. 如果方法传递的是多个复杂类型参数,比如 学生类Student 和 简单数据类型:简单数据类型使用 #{ arg+参数下标 }或者#{ param+参数位置 },复杂数据类型使用 #{ arg+参数下标.属性名 }或者#{ param+参数位置.属性名 }
select name, age from student where id = #{ arg0 } and sex = #{ arg1.name } 
  1. 如果在接口方法中的参数使用了@Param(“参数名”)注解:在就必须使用 #{ 参数名 }
<insert id="addStudent">
		insert into mybatis.student (name, age, address, email)
		values (#{name},#{age},#{address},#{email})
</insert>

二、删除(delete)

在stuentMapper.xml文件中定义delete标签,id对应的接口中的方法名,没有返回值类型

根据条件查询的时候,方法传递了参数 int id,所以可以通过#{id} / #{arg0} / #{param1}的方式进行占位匹配

<delete id="deleteStudent">
    delete
    from mybatis.student
    where id = #{param1}
</delete>

三、修改(update)

在stuentMapper.xml文件中定义update标签,id对应的接口中的方法名,没有返回值类型

<update id="updateStudent">
    update mybatis.student
    set name = #{arg0.name}
    where id = #{arg1}
</update>

四、查询(select)

在stuentMapper.xml文件中定义select标签,id对应的接口中的方法名,返回值类型为一条数据行对应的实体类的类型,如上文的student

<select id="getStudent" resultType="student">
    select id, name, age, address, email
    from mybatis.student
    where id = #{arg0}
</select>

主键回传

主键回填的应用场景: 如果一个业务,需要增加一条记录,然后还需要增加的相关的记录,这个相关的记录就需要使用到前一条记录的主键。

需要在studentMapper.xml文件中的插入标签中增加一个insert标签

注意点:

  • useGeneratedKeys="true"表示使用自动生成的键
  • parameterType="student"表示参数类型为student
  • selectKey标签定义了一个查询键,用于获取插入操作后的主键值。键属性为id,结果类型为int,查询语句为select last_insert_id();,查询结果将赋值给studentid属性。
<insert id="addStudent" useGeneratedKeys="true" parameterType="student">
    <selectKey keyProperty="id" resultType="int" order="AFTER">
        select last_insert_id();
    </selectKey>
    insert into mybatis.student (name, age, address, email)
    values (#{name}, #{age}, #{address}, #{email})
</insert>

Java代码

Student student = new Student();
student.setName("南宫婉");
student.setAge(24);
student.setAddress("楚国");
student.setEmail("wiydgsu@gmail.com");
int i = mapper.addStudent(student);
Integer id = student.getId();
System.out.println("回填的主键是:" + id);//回填的主键是:6

结果映射

在实际情况中,很有可能出现设计的实体类的属性名与数据表的字段不匹配的情况

针对这种情况,Mybatis提供了结果集映射,供用户自己实现数据库中的字段与实体类的属性匹配

创建一个teacher表,并插入数据

CREATE TABLE teacher
(
    t_id   INT PRIMARY KEY AUTO_INCREMENT,
    t_name VARCHAR(255),
    t_age  INT
);

INSERT INTO teacher (t_name, t_age)
VALUES ('张三', 30),
       ('李四', 40),
       ('王五', 50),
       ('赵六', 60),
       ('孙七', 70);

创建一个Teacher类,其中的字段与数据表并不匹配

@Data
public class Teacher {

	private Integer id;
	private String name;
	private Integer age;
}

创建teacherMapper接口并定义查询方法

public interface TeacherMapper {
	// 获取学生列表
	List<Teacher> getTeachers();
}

创建teacherMapper.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="cn.cnmd.mapper.TeacherMapper">

    <!--定义了一个resultMap来定义映射关系
	property代表实体类的属性
	column代表数据表的列名
	-->
	<resultMap id="resultMap" type="teacher">
		<id property="id" column="t_id"/>
		<result property="name" column="t_name"/>
		<result property="age" column="t_age"/>
	</resultMap>

	<select id="getTeachers" resultMap="resultMap"><!--指定映射的map为resultMap-->
		select t_id, t_name, t_age
		from mybatis.teacher;
	</select>

</mapper>

Java代码

TeacherMapper teacherMapper = session.getMapper(TeacherMapper.class);
List<Teacher> teachers = teacherMapper.getTeachers();
teachers.forEach(System.out::println);

查询结果,可以看到实体类的属性与表列名对应上了

Teacher(id=1, name=张三, age=30)
Teacher(id=2, name=李四, age=40)
Teacher(id=3, name=王五, age=50)
Teacher(id=4, name=赵六, age=60)
Teacher(id=5, name=孙七, age=70)

注意:Mybatis只是提供了结果集映射,并不是一定要使用,直接在查询语句中为表字段名取别名可以不使用结果映射

因为查询的结果返回的是一张虚拟表,表的列名就是别名

select t_id id, t_name name, t_age age from teacher;

联级查询

数据表存在一对一的关系,一对多的关系,多对多的关系

多对多的关系就是多个一对多关系的组合,并借助中间表来实现

这里的联级查询就只由一对一联级查询、一对多联级查询

一对一联级查询

一对一的情况就是一张表只与另一张表关联,比如老师对学生进行一对一辅导对应的一对一关系

准备数据表my_student,my_teacher

CREATE TABLE my_student
(
    id         INT PRIMARY KEY auto_increment,
    name       VARCHAR(255),
    teacher_id INT,
    FOREIGN KEY (teacher_id) REFERENCES my_teacher (id)
);

CREATE TABLE my_teacher
(
    id   INT PRIMARY KEY auto_increment,
    name VARCHAR(255)
);

INSERT INTO my_student (id, name, teacher_id)
VALUES (1, '张三', 1),
       (2, '李四', 2);

INSERT INTO my_teacher (id, name)
VALUES (1, '王五'),
       (2, '赵六');

两个实体类MyStudent、MyTeacher

@Data
public class MyTeacher {

	private Integer id;
	private String name;
}
//------------------------------------------------------------
@Data
public class MyStudent {

	private Integer id;
	private String name;
	private Integer teacherId;
}

创建studentTeacherMapper接口

public interface StudentTeacherMapper {

	List<MyStudent> getStudents();

}

创建studentTeacherMapper.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="cn.cnmd.mapper.StudentTeacherMapper">

	<resultMap id="resultMap" type="MyStudent">
		<id property="id" column="id"/>
		<result property="name" column="name"/>
		<association property="myTeacher" column="{id = id}" select="getTeacher"/>
	</resultMap>


	<select id="getStudents" resultMap="resultMap">
		select id, name, teacher_id
		from mybatis.my_student;
	</select>

	<select id="getTeacher" resultType="MyTeacher">
		select id, name
		from mybatis.my_teacher where id = #{id};
	</select>
    
    <!-- <resultMap id="resultMap2" type="myStudent"> -->
	<!-- 	<id property="id" column="id"/> -->
	<!-- 	<result property="name" column="name"/> -->
	
	<!-- 	<association property="teacher" javaType="myTeacher"> -->
	<!-- 		<id property="id" column="teacherId"/> -->
	<!-- 		<result property="name" column="teacherName"/> -->
	<!-- 	</association> -->
	<!-- </resultMap> -->
	
	<!-- <select id="getStudents" resultMap="resultMap2"> -->
	<!-- 	select stu.id, stu.name, tea.id as teacherId, tea.name as teacherName -->
	<!-- 	from mybatis.my_student stu -->
	<!-- 	inner join mybatis.my_teacher tea -->
	<!-- 	where tea.id = stu.teacher_id; -->
	<!-- </select> -->


</mapper>

Java代码

StudentTeacherMapper mapper = session.getMapper(StudentTeacherMapper.class);
List<MyStudent> students = mapper.getStudents();
students.forEach(System.out::println);

结果

MyStudent(id=1, name=张三, myTeacher=MyTeacher(id=1, name=王五))
MyStudent(id=2, name=李四, myTeacher=MyTeacher(id=2, name=赵六))

一对多联级查询

品牌和产品的关系就是一对多的关系,比如苹果和水果拼盘都属于苹果品牌,香蕉属于香蕉品牌

新建表brand、product

# 一对多的关系
CREATE TABLE product
(
    id       INT PRIMARY KEY,
    name     VARCHAR(255),
    brand_id INT,
    FOREIGN KEY (brand_id) REFERENCES brand (id)
);

CREATE TABLE brand
(
    id   INT PRIMARY KEY,
    name VARCHAR(255)
);

INSERT INTO product (id, name, brand_id)
VALUES (1, '苹果', 1),
       (2, '香蕉', 2),
       (3, '水果拼盘', 1);

INSERT INTO brand (id, name)
VALUES (1, '苹果品牌'),
       (2, '香蕉品牌');

创建实体类Brand、Product

@Data
public class Brand {
	private Integer id;
	private String name;
	private List<Product> products;
}
//------------------------------------------
@Data
public class Product {
	private Integer id;
	private String name;
	private Integer bandId;
}

定义BrandMapper接口

public interface BrandMapper {

	List<Brand> getBrands();
}

创建brandMapper.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="cn.cnmd.mapper.BrandMapper">

        <!-- 方案一 -->
	<resultMap id="getBrandsMap" type="brand">
		<id property="id" column="id"/>
		<result property="name" column="name"/>
		<collection property="products" column="{brandId = id}" select="getProducts">
			<id property="id" column="id"/>
			<result property="name" column="name"/>
			<result property="brandId" column="brand_id"/>
		</collection>
	</resultMap>

	<select id="getBrands" resultMap="getBrandsMap">
		select id, name
		from mybatis.brand;
	</select>

	<select id="getProducts" resultType="product">
		select id, name, brand_id
		from mybatis.product
		where brand_id = #{brandId}
	</select>
    
    <!-- 方案二 -->
    
	<!-- <resultMap id="map" type="brand"> -->
	<!-- 	<id property="id" column="id"/> -->
	<!-- 	<result property="name" column="name"/> -->
	<!-- 	<collection property="products" ofType="product"> -->
	<!-- 		<id property="id" column="productId"/> -->
	<!-- 		<result property="name" column="productName"/> -->
	<!-- 		<result property="brandId" column="belongToBrand"/> -->
	<!-- 	</collection> -->
	<!-- </resultMap> -->
	
	<!-- <select id="getBrands" resultMap="map"> -->
	<!-- 	select b.id, b.name, p.id productId, p.name productName, p.brand_id belongToBrand -->
	<!-- 	from mybatis.brand b -->
	<!-- 			 inner join mybatis.product p -->
	<!-- 	where b.id = p.brand_id -->
	<!-- </select> -->

</mapper>

Java代码

BrandMapper mapper = session.getMapper(BrandMapper.class);
List<Brand> brands = mapper.getBrands();
brands.forEach(System.out::println);

查询结果

Brand(id=1, name=苹果品牌, products=[Product(id=1, name=苹果, brandId=1), Product(id=3, name=水果拼盘, brandId=1)])
Brand(id=2, name=香蕉品牌, products=[Product(id=2, name=香蕉, brandId=2)])
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拖把湛屎,戳谁谁死

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值