文章目录
1.Mybatis
1.1JDBC操作
//利用jdbc,完成新增的功能
private static void method2() throws Exception{
//1,注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2,获取数据库的连接
//数据传输协议 数据库的ip 端口号 数据库名
String url = "jdbc:mysql://localhost:3306/cgb2107";
Connection c = DriverManager.getConnection(url,"root","root");
//3,获取传输器
Statement s = c.createStatement();
//4,利用传输器执行 增删改的SQL
//executeUpdate()用来执行增删改的SQL,只返回影响行数
int rows = s.executeUpdate(
"INSERT INTO emp(ename,job) VALUES('rose','副总')");
//5,释放资源
//r.close();//结果集
s.close();//传输器
c.close();//连接
}
1.2Mybatis概述
- MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。
- MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
- MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java
Objects,普通老式 Java 对象)为数据库中的记录。 - MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation
迁移到了google code,并且改名为MyBatis 。 - 2013年11月迁移到Github。
特点:
- 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
- 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。
- sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
- 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
- 提供映射标签,支持对象与数据库的orm字段关系映射。
- 提供对象关系映射标签,支持对象关系组建维护。
- 提供xml标签,支持编写动态sql。
1.3数据映射
持久层:
1.数据表: 用户的数据信息, 持久化到本地磁盘中
2.POJO: 程序通过对象封装数据信息.
映射关系: 一个POJO对象要求映射一张数据表
1.对象名称 映射 数据表表名
2.对象的属性 映射 数据表中的字段
1.4环境搭建
1.4.1导入jar包文件
<!--mybatis依赖包-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<!--jdbc依赖包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--添加lombok的包-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
1.4.2编辑mybatis-config.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="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/jt?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--Mybatis加载Mapper映射文件-->
<mappers>
<mapper resource="mybatis/mappers/UserMapper.xml"/>
</mappers>
</configuration>
1.4.3编辑UserMapper.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是mybaits映射文件的唯一标识,与接口对应-->
<mapper namespace="com.jt.mapper.UserMapper">
<!--id 表示接口方法
resultType 返回值结果类型
-->
<select id="findAll" resultType="com.jt.pojo.User">
select * from demo_user
</select>
</mapper>
1.5Mybatis运行原理
package com.jt;
import com.jt.mapper.UserMapper;
import com.jt.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class TestMybatis {
/**
* 规则说明:
* 1.创建SqlSessionFactory 工厂模式
* 2.获取SqlSession 理解:数据库链接+传输器对象
* 3.获取Mapper接口对象
* 4.完成业务调用
* 5.关闭链接
*/
@Test
public void demo1() throws IOException {
//1.1 指定配置文件的根目录
String resource = "mybatis-config.xml";
//1.2 通过IO流 加载配置文件 org.apache.ibatis.io;包路径
InputStream inputStream = Resources.getResourceAsStream(resource);
//1.3 实例化工厂对象
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(inputStream);
//2 获取SqlSession 通过sqlSession可以直接操作数据库
SqlSession sqlSession = sqlSessionFactory.openSession();
//3 获取接口对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//4.调用接口方法
List<User> userList = userMapper.findAll();
System.out.println(userList);
//5.暂时手动关闭链接
sqlSession.close();
}
}
2.SpringBoot简化Mybatis
2.1修改配置文件名称为.yml
2.2修改yml配置文件
#1.配置端口号 注意缩进!!!!!
server:
port: 8090
#2.配置数据源
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/jt?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
username: root
#yml文件 0不解析 如果字母以0开头则引号包裹
#password: "0123456"
password: root
#3.配置Mybatis
mybatis:
type-aliases-package: com.jt.pojo
#将所有的映射文件全部加载
mapper-locations: classpath:/mappers/*.xml
#开启驼峰映射
configuration:
map-underscore-to-camel-case: true
#4.打印Sql com.jt.mapper下的Sql日志
logging:
level:
com.jt.mapper: debug
3.resultMap
当表中的字段与POJO中的属性名称不一致时,需要使用resultMap的方式进行映射.
resultType : 只能支持字段名称与属性名称一致时才能自动映射.
resultMap: 可以支持 任意类型的映射 万能的结构
3.1编辑映射文件
<?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="com.jt.mapper.DogMapper">
<select id="findAll" resultMap="dogRM">
select * from dog
</select>
<resultMap id="dogRM" type="Dog">
<!--ID:代表主键-->
<id column="dog_id" property="dogId"/>
<!--结果集-->
<result column="dog_name" property="dogName"/>
<!--<result column="age" property="age"/>-->
</resultMap>
</mapper>
3.2开启驼峰规则映射
mybatis:
#定义别名包
type-aliases-package: com.jt.pojo
#将所有的映射文件全部加载
mapper-locations: classpath:/mappers/*.xml
#开启驼峰映射
configuration:
map-underscore-to-camel-case: true
4.Mybatis关联查询
4.1关联查询sql
4.1.1笛卡尔积
特点: 只获取2张表的交集
SELECT * FROM emp,dept
WHERE emp.dept_id = dept.dept_id
4.1.2连接查询
分类: 1.左连接 2.内连接 3.右连接
/*左连接 emp表当作主表 */
SELECT * FROM
emp
LEFT JOIN
dept
ON
emp.dept_id = dept.dept_id
4.2封装关联关系
4.2.1封装Emp对象
package com.jt.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class Emp implements Serializable {
private Integer id;
private String name;
private Integer age;
//关联关系: 一个员工对应一个部门
private Dept dept;
//private Integer deptId;
}
4.2.2封装Dept对象
package com.jt.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class Dept implements Serializable {
private Integer deptId;
private String deptName;
//关联 一个部门下有多个员工
private List<Emp> emps;
}
4.2.3编辑映射文件(一对一封装)
<?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="com.jt.mapper.EmpMapper">
<!--
规则:
1.如果操作单表 一般使用resultType
2.如果进行关联操作,使用resultMap
3.如果是多表关联操作,则不允许出现重名字段.否则映射失败.
-->
<select id="findAll" resultMap="empRM">
SELECT emp.id,emp.name,emp.age,dept.dept_id,
dept.dept_name
FROM emp,dept
WHERE emp.dept_id = dept.dept_id
</select>
<!--
关于自动映射规则:
1.没有关联映射时: 如果属性和字段同名,则可以省略不写.
2.如果有关联映射: 则需要添加自动映射的开关autoMapping="true"
该注解只对当前对象有效 如果有多个对象,则需要添加多次
-->
<resultMap id="empRM" type="Emp" autoMapping="true">
<!--主键是必填项-->
<id column="id" property="id"/>
<!--
知识点:
1.一对一关联封装 association标签
2.必须指定属性的类型 javaType属性
3.autoMapping="true" 自动映射
-->
<association property="dept" javaType="Dept" autoMapping="true">
<!--主键必填项-->
<id column="dept_id" property="deptId"/>
<!--由于一起开启驼峰规则映射.所以下列的操作可以省略-->
<!--<result column="dept_name" property="deptName"/>-->
</association>
</resultMap>
</mapper>
4.2.3编辑映射文件(一对多封装)
<?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="com.jt.mapper.DeptMapper">
<select id="findAll" resultMap="deptRM">
SELECT dept.dept_name,emp.*
FROM dept,emp
WHERE emp.dept_id = dept.dept_id
</select>
<resultMap id="deptRM" type="Dept" autoMapping="true">
<!--主键必须标识-->
<id column="dept_id" property="deptId"/>
<!-- 一对多封装 固定搭配 ofType="" -->
<collection property="emps" ofType="Emp" autoMapping="true">
<id column="id" property="id"></id>
</collection>
</resultMap>
</mapper>
5.总结
知识点1
/**
* 知识点:
* 1.如果是多个参数传递,则一般采用对象的方式封装.
*/
@Test
public void testFindByNA(){
String name = "孙尚香";
int age = 18;
User user = new User();
user.setName(name).setAge(age);
List<User> userList = userMapper.findUserByNA(user);
System.out.println(userList);
}
知识点2
<!-- 根据name和age查询数据
知识点: 别名包
在配置文件中指定包路径: 可以自动的实现包路径的拼接
resultType规则:
1. 首先根据别名包匹配.设定..
2. 如果匹配不成功,则按照路径匹配.
参数传递的规则:
1. 如果是单个参数,则使用#{key} 获取的参数的值
2. 如果是对象参数,则使用#{属性} 获取的是属性值
-->
<select id="findUserByNA" resultType="User">
select * from demo_user where
name = #{name} and age = #{age}
</select>
知识点3:Map封装对象
/**
* 知识点3:
* 说明: 如果多个参数不方便使用 User对象封装时,应该使用万能的集合Map
*/
@Test
public void testFindByAge(){
int minAge = 18;
int maxAge = 100;
Map<String,Integer> map = new HashMap<>();
map.put("minAge",minAge);
map.put("maxAge",maxAge);
List<User> userList = userMapper.findUserByAge(map);
System.out.println(userList);
}
知识点4:转义标签
<!--
根据年龄查询数据
语法: 如果传递的参数是Map, 则使用#{key}
xml转译字符:
1. > >
2. < <
3. & &
4. 万能转译字符
<![CDATA[ 转移内容 ]]>
-->
<select id="findUserByAge" resultType="User">
<![CDATA[
select * from demo_user
where age > #{minAge} and age < #{maxAge}
]]>
</select>
知识点5:@Param实现数据封装
/**
* 知识点4:
* 利用注解实现数据的封装
*/
@Test
public void testFindByAge2(){
int minAge = 18;
int maxAge = 100;
List<User> userList = userMapper.findUserByAge2(minAge,maxAge);
System.out.println(userList);
}
//原则:Mybatis只支持单值传参 将多值封装为单值
//注解:@Param("key") int minAge(值)
// 作用:将数据封装为Map
List<User> findUserByAge2(@Param("minAge") int minAge, @Param("maxAge") int maxAge);
知识点6:模糊查询
/**
* 知识点5:
* 利用注解实现数据的封装
*/
@Test
public void testFindUserByLike(){
String name = "%" + "君" + "%";
List<User> userList = userMapper.findUserByLike(name);
System.out.println(userList);
}
<!--模糊查询 特别注意表名的大小写问题!!!!!
windows系统中: 不区分大小写
Linux系统中: 区分大小写问题.
-->
<select id="findUserByLike" resultType="User">
SELECT * FROM demo_user WHERE NAME LIKE #{name}
</select>
方式2: xml配置文件动态拼接%
<!--模糊查询 特别注意表名的大小写问题!!!!!
windows系统中: 不区分大小写
Linux系统中: 区分大小写问题.
语法: "%" 这样的方式
-->
<select id="findUserByLike" resultType="User">
SELECT * FROM demo_user WHERE NAME LIKE "%"#{name}"%"
</select>
知识点7:Sql标签
说明: Sql语句中经常出现重复的数据.如果每次重复的内容都自己手写.则开发的效率低.
优化: 将公共的Sql进行抽取
优势: Sql标签可以节省代码
缺点: 可读性变差了, 如果是关联操作 则根据情况而定.
<!--Sql标签: 抽取公共的Sql语句 -->
<sql id="tableColumn">
id,name,age,sex
</sql>
知识点8:集合参数写法,动态
select * from demo_user where id in (1,2,3,5,7........)
//前端: URL?id=1,2,3,4,5 获取之后一般采用数组接收
@Test
public void testFindListByIn(){
int[] array = {1,2,3,5,7};
List<User> userList = userMapper.findListByIn(array);
System.out.println(userList);
}
<!--
关于Mybatis的遍历的写法
foreach:
1. collection 需要遍历的集合
1.1 数组 关键字: array/list
1.2 list集合 关键字: list/array
1.3 Map<key,array/list> 关键字:key
2. open/close 循环体的开始和结束 可以写到循环之外简化标签
3. item 当前遍历数据的变量名
4. separator 分割符
-->
<select id="findListByIn" resultType="User">
select * from demo_user where id in (
<foreach collection="array" item="id" separator=",">
#{id}
</foreach>
)
</select>
知识点9:用户新增
@Test
public void testInsertUser(){
User user = new User();
user.setName("张三").setAge(18).setSex("男");
userMapper.saveUser(user);
System.out.println("新增成功!!!!");
}
<insert id="saveUser">
insert into demo_user(id,name,age,sex)
value (null, #{name},#{age},#{sex})
</insert>
知识点10:动态Sql-where
package com.jt;
import com.jt.mapper.UserMapper;
import com.jt.mapper.UserMapper2;
import com.jt.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@SpringBootTest
public class TestMybatis2 {
@Autowired
private UserMapper2 userMapper;
/**
* 案例1: 测试动态sql
*/
@Test
public void testDemo1(){
User user = new User();
user.setAge(18).setSex("女"); //动态变化的数据
List<User> userList = userMapper.findUserList(user);
System.out.println(userList);
}
}
<?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="com.jt.mapper.UserMapper2">
<!--
动态Sql: 根据对象中不为null的属性当作where条件
语法:
1.如果判断成立,则动态拼接条件
<if test="id !=null ">条件</if>
2.where标签 去除where后边多余的一个and/or
-->
<select id="findUserList" resultType="User">
select * from demo_user
<where>
<if test="id !=null ">id = #{id}</if>
<if test="name !=null">and name = #{name}</if>
<if test="age !=null ">and age = #{age}</if>
<if test="sex !=null ">and sex = #{sex}</if>
</where>
</select>
</mapper>
知识点11:动态Sql-set
//执行动态的更新操作
//根据对象中不为null的元素,充当set条件. where id=xxx
@Test
public void testDemo2(){
User user = new User();
user.setId(231).setName("冬天").setAge(18);
userMapper.updateUser(user);
System.out.println("更新成功!!!");
}
<!--根据对象中不为null的元素,充当set条件.-->
<update id="updateUser">
update demo_user
<set>
<if test="name !=null">name = #{name},</if>
<if test="age !=null">age = #{age},</if>
<if test="sex !=null">sex = #{sex}</if>
</set>
where id = #{id}
</update>
知识点12:动态Sql-choose、when、otherwise
说明: 如果不想使用所有的条件可以使用choose 类似于java中的switch 语法:
如果name有值,则按照name查询,否则按照sex查询数据.
@Test
public void testDemo3(){
User user = new User();
user.setName(null).setAge(null).setSex("女");
List<User> userList = userMapper.findUserByNS(user);
System.out.println(userList);
}
<select id="findUserByNS" resultType="User">
select * from demo_user
<where>
<choose>
<when test="name !=null">
name = #{name}
</when>
<when test="age !=null">
age = #{age}
</when>
<otherwise>
sex = #{sex}
</otherwise>
</choose>
</where>
</select>