文章目录
如何外部导入jar包
外部加载引入jar包:(jar文件夹不能发生改变或者删除,好处只需往这个文件里面加入jar包项目就可以自动加载jar包,无需另外的导入)
导入的过程和mybatis的项目结构:
mybatis项目项目架构(这里建立的是java项目)
建立放置配置文件的包
mybatis的简介
MyBatis,实质上 Mybatis 对 ibatis 进行一些改进。
MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架。MyBatis 消 除了几乎所有的 JDBC 代码和参数的手工设置以及结果集的检索。MyBatis 使用简单的 XML 或注解用于配置和原始映射,将接口和 Java 的 POJOs(Plan Old Java Objects,普通的 Java 对象)映射成数据库中的记录。
Mybatis是一个orm框架(Object relation Mapping),持久层技术,支持动态sql调用,存储过程调用(数据库编程 for if in out),sql和java代码显示分离。(高内聚 低耦合)提高程序的扩展性和维护性。
mybatis的执行流程
分析:
1.mybatis 配置文件,包括 Mybatis 全局配置文件和 Mybatis 映射文件,其中全局配 置文件配置了数据源、事务等信息;映射文件配置了 SQL 执行相关的信息。
2.mybatis 通过读取配置文件信息(全局配置文件和映射文件),构造出 SqlSessionFactory,即会话工厂。
\3. 通过 SqlSessionFactory,可以创建 SqlSession 会话。Mybatis 是通过 SqlSession 来操作数据库的。
4.SqlSession 本身不能直接操作数据库,它是通过底层的 Executor 执行器接口来操作数据库的。Executor 接口有两个实现类,一个是普通执行器,一个是缓存执行器(默认)。
Executor 执行器要处理的 SQL 信息是封装到一个底层对象 MappedStatement 中。该对 象包括:SQL 语句、输入参数映射信息、输出结果集映射信息。其中输入参数和输出结果 的映射类型包括 java 的简单类型、HashMap 集合对象、POJO 对象类型。
看到 Mybatis 的框架图,可以清晰的看到 Mybatis 的整体核心对象,用图来表达 Mybatis 的整个的执行流程。如下图所示:
原理详解:
MyBatis 应用程序根据 XML 配置文件创建 SqlSessionFactory,SqlSessionFactory 再根据配置,配置来源于两个地方,一处是配置文件,一处是 Java 代码的注解,获取一 个 SqlSession。SqlSession 包含了执行 sql 所需要的所有方法,可以通过 SqlSession 实例直接运行映射的 sql 语句,完成对数据的增删改查和事务 交等,用完之后关闭 SqlSession。
环境搭建
1: 引入当前框架的主体结构(***.jar)
mybatis.jar: mybatis 的核心包
mysql.jar: 驱动包
log4j……jar: 日志工具包
及mydatis相关的依赖包
2: 数据库新建表并添加测试数据
3.创建项目,建立相应目录文件
4.建立实体类
public class Person implements Serializable {
private int id;
private String name;
private Date bir;
private String address;
5: mybatis-config.xml 编写
Mybatis的环境配置:
事务配置 数据源配置 加载mapper.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>
<!--起别名-->
<typeAliases>
<!-- 直接扫描实体类的包,在mapper.xml使用到全路径的实体类直接写实体类的名 -->
<package name="com.study.homework.entity"/>
</typeAliases>
<environments default="development">
<!-- 开发的环境 -->
<environment id="development">
<!-- 事务控制 JDBC事务管理 -->
<transactionManager type="JDBC"/>
<!-- 数据库 连接池的技术-->
<dataSource type="POOLED">
<!-- <property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://localhost:3306/user_db?useUnicode=true&characterEncoding=utf-8&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="admin"/>-->
<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接口和接口方法的映射 -->
<mappers>
<mapper resource="com/study/homework/mapper/StudentMapper.xml"/>
</mappers>
</configuration>
-
日志log4j.properties的配置
log4j.rootLogger=DEBUG, stdout # Console output... log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
数据库配置文件:db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/user_db?characterEncoding=utf-8
jdbc.username=root
jdbc.password=admin
7配置mapper.xml
1)构建一个mapper接口(定义操作数据库的方法)
package com.study.homework.mapper;
import com.study.homework.entity.Student;
import java.util.List;
public interface StudentMapper {
/* 1、查看所有学员信息
2、按姓名查看学员信息(学员可同名)
3、按id查看学员信息
4、新增学员信息
5、通过id删除学员信息
6、通过id修改学员信息
7、统计班级人数*/
List<Student> studentAll();//查看所有学员信息
List<Student> studentByName(String name);//按姓名查看学员信息(学员可同名)
Student seleteById(int id);//按id查看学员信息
int insertStudent(Student student);//新增学员信息
//如果这里是用来integer类型,xml配置文件里面的参数类型就要使用integer的全路径加类名
int deleteStudentById(int id);//通过id删除学员信息
int updateStudentById(Student student);//通过id修改学员信息
int countStudent();//统计班级人数
}
2)定义一个和接口名称相同的配置文件***Mapper.xml
注意:Namespace: 必须和我们mapper接口全部限定名称一致的
各种操作标签 : insert delete update select
<?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.study.homework.mapper.StudentMapper">
<!-- 查询所有 -->
<select id="studentAll" resultType="Student">
select * from student
</select>
<!-- 按照条件查询-->
<select id="studentByName" parameterType="string" resultType="Student">
select * from student where name=#{name}
</select>
<!-- 按照id查询-->
<select id="seleteById" parameterType="int" resultType="Student">
select * from student where name=#{id}
</select>
<insert id="insertStudent" parameterType="Student">
INSERT INTO `student`(`name`, `sex`, `age`, `address`, `tel`, `email`)
VALUES ( #{name}, #{sex}, #{age}, #{address}, #{tel}, #{email});
</insert>
<!--执行单元
添加 insert
id:对应接口的方法名 实现哪个方法
parameterType:参数类型 自定义类,完全限定名
返回值类型,一般可以不用写 insert,update,delete默认返回值类型为int
读取参数对象中的属性:#{属性名}
-->
<!--参数类型:这里面的id或者其他是这个对象的成员名-->
<update id="updateStudentById" parameterType="Student">
update student SET `name` = #{name}, sex = #{sex}, age = #{age},
address = #{address}, tel = #{tel}, email = #{email} WHERE id = #{id};
</update>
<!--参数类型:#{id}这个id是接口方法写的参数名-->
<delete id="deleteStudentById" parameterType="int">
delete from student where id=#{id}
</delete>
<select id="countStudent" resultType="int">
select count(*) from student;
</select>
</mapper>
8: 创建测试类(这是另外一个实体类的测试)
public class App {
@Test
public void testSave(){
//加载全局置文件
String fileName="mybatis-config.xml";
try {
//Resources是mybatis中提供的一个工具类
InputStream inputStream = Resources.getResourceAsStream(fileName);
//创建工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂拿到一个会话
try (SqlSession sqlSession = factory.openSession()) {
//通过反射拿到接口
PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
Person person=new Person(0,"张三直",new Date(),"广东");
int result = mapper.save(person);
//提交事务 增删改
sqlSession.commit();
sqlSession.close();
if(result>0){
System.out.println("添加成功");
}else{
System.out.println("添加失败");
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void testUpdate(){
//加载全局置文件
String fileName="mybatis-config.xml";
try {
//Resources是mybatis中提供的一个工具类
InputStream inputStream = Resources.getResourceAsStream(fileName);
//创建工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂拿到一个会话
try (SqlSession sqlSession = factory.openSession()) {
//通过反射拿到接口
PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
Person person=new Person(6,"张六",new Date(),"广东");
int result = mapper.update(person);
//提交事务 增删改
sqlSession.commit();
sqlSession.close();
if(result>0){
System.out.println("修改成功");
}else{
System.out.println("修改失败");
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void testRmove(){
//加载全局置文件
String fileName="mybatis-config.xml";
try {
//Resources是mybatis中提供的一个工具类
InputStream inputStream = Resources.getResourceAsStream(fileName);
//创建工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂拿到一个会话
try (SqlSession sqlSession = factory.openSession()) {
//通过反射拿到接口
PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
int result = mapper.remove(8);
//提交事务 增删改
sqlSession.commit();
sqlSession.close();
if(result>0){
System.out.println("修改成功");
}else{
System.out.println("修改失败");
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
//无关的测试但是有注释
@Test
public void updateText(){
try {
//定义配置文件路径,这里默认是从resource开始,以resource作为根目录
String fileName = "mybatis-config.xml";//实际的文件目录地址如果resource下直接写文件名但是不能在前面加/
InputStream resource = Resources.getResourceAsStream(fileName);//获取全局配置文件的字节流对象
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resource);//获取sqlsession工厂
SqlSession sqlSession = build.openSession();//获取sqlsession对象获取操作数据的方法
PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);//通过反射获
Person person=new Person();
person.setId(2);
person.setAddress("上海");
person.setBir(new Date());
person.setName("火影");
int i = mapper.update(person);//取接口对象的方法
sqlSession.commit();//提交事物,刷新数据库,将数据写入
sqlSession.close();//关闭流
if (i>0){
System.out.println("成功");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
多个参数传递的问题
1: @Param (“名称”) 就是在我们sql语句中使用的变量名(推荐)
#{名称}
2: 使用map集合的传参
#{key}
3: 使用参数的下标
#{arg0}。。。。。
示例代码
接口
//@Param(“名称”) 就是在我们sql语句中使用的变量名
int saveByParam(@Param("id") int id, @Param("name") String name,@Param("bir") Date bir, @Param("address") String address);
//使用map集合的传参 key-value 执行单元#{key名称}
int saveByMap(Map<String,Object> map);
//使用参数的下标
int saveByIndex(int id,String name,Date bir,String address);
对应的Mapper
<!-- 通过参数下标 @Param(“名称”)属性不需要设置 #{名称} **推荐**-->
<insert id="saveByParam" parameterType="com.study.mybatis.pojo.Person">
INSERT INTO `person`(`id`, `name`, `bir`, `address`)
VALUES (#{id},#{name},#{bir},#{address});
</insert>
<!-- #{key名称} -->
<insert id="saveByMap" parameterType="java.util.Map">
INSERT INTO `person`(`id`, `name`, `bir`, `address`)
VALUES (#{id},#{name},#{bir},#{address});
</insert>
<!--
#{arg下标}从0开始
#{param下标} 从1开始
-->
<insert id="saveByIndex" parameterType="java.util.Map">
INSERT INTO `person`(`id`, `name`, `bir`, `address`)
VALUES (#{param1},#{param2},#{param3},#{param4});
</insert>
测试方法
@Test
public void testSaveByParam(){
String fileName="mybatis-config.xml";
try {
InputStream inputStream = Resources.getResourceAsStream(fileName);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = factory.openSession();//alt+enter
PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Date parse = format.parse("2019-12-31");
int result = mapper.saveByParam(0, "jack", parse, "广东");
sqlSession.commit();
sqlSession.close();
System.out.println(result);
} catch (IOException | ParseException e) {
e.printStackTrace();
}
}
@Test
public void testSaveByMap(){
String fileName="mybatis-config.xml";
try {
InputStream inputStream = Resources.getResourceAsStream(fileName);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = factory.openSession();//alt+enter
PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Date parse = format.parse("2019-12-31");
Map<String,Object> map=new HashMap<>();
map.put("id",0);
map.put("name","xixi");
map.put("bir",parse);
map.put("address","广东");
int result = mapper.saveByMap(map);
sqlSession.commit();
sqlSession.close();
System.out.println(result);
} catch (IOException | ParseException e) {
e.printStackTrace();
}
}
@Test
public void testSaveByIndex(){
String fileName="mybatis-config.xml";
try {
InputStream inputStream = Resources.getResourceAsStream(fileName);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = factory.openSession();//alt+enter
PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Date parse = format.parse("2019-12-31");
int result = mapper.saveByIndex(0, "tomer123", parse, "广东");
sqlSession.commit();
sqlSession.close();
System.out.println(result);
} catch (IOException | ParseException e) {
e.printStackTrace();
}
}
主键值:
Mybatis: 标签 selectKey 帮助我们获取数据库管理的主键值
利用一下我们数据库查询主键值的方式
1) increment select last_insert_id()
2) uuid() select uuid(); -- mysql数据库生成一个全球唯一不重复的字符串
示例代码
接口
public int save(Person per);
对应的mapper
<!-- 返回保存了当前对象的主键值
keyProperty: 类中的主键字段匹配的属性
keyColumn: 表中的那个字段是主键字段
order: BEFORE(先获取主键然后再插入数据) AFTER(先插入数据,在获取主键)
resultType: 主键的类型是什么
-->
<insert id="save" parameterType="com.study.mybatis.pojo.Person">
<selectKey keyProperty="id" keyColumn="id" order="AFTER" resultType="int">
select LAST_INSERT_ID();
</selectKey>
INSERT INTO `person`(`id`, `name`, `bir`, `address`)
VALUES (#{id},#{name},#{bir},#{address});
</insert>
测试类:
public void testSaveInfo() {
//定义配置文件路径
String fileName="mybatis-config.xml";
try {
//通过配置文件创建输入流对象
InputStream inputStream = Resources.getResourceAsStream(fileName);
//读取配置文件 实例化我们工厂
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = factory.openSession();
//通过反射机制获取接口对象
PersonMapper mapper = session.getMapper(PersonMapper.class);
//创建对象
Person person=new Person(11,"孙芳",new Date(),"广州市");
//调用接口方法
int result = mapper.saveInfo(person);
//增删改操作需提交事务
session.commit();
//关闭
session.close();
System.out.println("受影响行数:"+result);
//获取方式
System.out.println("插入后 id:"+person.getId());
} catch (IOException e) {
e.printStackTrace();
}
}
查询操作
接口
//单个对象查询
Person getById(int id);
//查集合
List<Person> list();
//查数值
int count();
mapper.xml
<!-- resultType 指的是返回值类型
要求:实体中的属性名要与表的中字段名要一致
确保返回的结果<=1条-->
//查询一个实例时候返回类型,就是实际要返回的类型的全路径包括包装类
<select id="getById" resultType="com.study.mybatis.pojo.Person" parameterType="int">
SELECT * FROM `person` WHERE `id`=#{id}
</select>
<!-- 当返回的是一个对象集合的时候,返回值类型是泛型指定的类型的全路径,包括包装类也是-->
//这么长的全类型名可在全局mybatis里使用别名来简化写法
<select id="list" resultType="com.study.mybatis.pojo.Person" >
SELECT * FROM `person`
</select>
<select id="count" resultType="int" >
SELECT COUNT(*) FROM `person`
</select>
测试:
@Test
public void testGetById(){
//加载全局置文件
String fileName="mybatis-config.xml";
try {
//Resources是mybatis中提供的一个工具类
InputStream inputStream = Resources.getResourceAsStream(fileName);
//创建工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂拿到一个会话
SqlSession sqlSession = factory.openSession();
//通过反射拿到接口
PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
System.out.println("------查单个-------");
Person person = mapper.getById(2);
System.out.println(person);
System.out.println("------查集合-------");
List<Person> list = mapper.list();
for (Person person1 : list) {
System.out.println(person1);
}
System.out.println("------查数值-------");
int count = mapper.count();
System.out.println("一共有:"+count);
sqlSession.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Sql片段
针对在mybatis配置文件中重复书写的sql内容,我们可以采用sql片段封装的方式完成,如果在其他的sql中使用,我们只需导入这个公共sql段
Sql段的定义:
<!-- 定义 SQL 片段 --> <!--
[sql 标签 ]:定义一个 SQL 片段 [id]:SQL 片段的唯一标识 建议:
1、SQL 片段中的内容最好是以单表来定义 2、如果是查询字段,则不要写上 SELECT 3、如果是条件语句,则不要写上 WHERE
-->
<sql id="select_user_where">
<if test="userExt != null">
<if test="userExt.sex != null and userExt.sex != ''">
AND sex = #{userExt.sex}
</if>
<if test="userExt.username != null and userExt.username != ''">
AND username LIKE '%${userExt.username}%'
</if>
</if>
</sql>
Sql段的使用
Sql中使用标签<include refid=”sql段定义的时候我们声明sql段的id值”>
<!-- 根据用户 id 来查询用户信息(使用 SQL 片段) -->
<!--
[include 标签 ]:引用已经定义好的 SQL 片段
[refid]:引用的 SQL 片段 id
-->
<select id="findUserList" parameterType="person" resultType="person">
SELECT * FROM person
<where>
<include refid="select_user_where"/>
</where>
</select>
自定义ResultMap(映射) & resultType(默认)
表中是字段和类中是属性不一致,导致我们查询的结果不符合预期类型。
<!-- 自定义的映射类型 -->
<resultMap type="com.study.bean.Person" id="newPerson">
<!-- 主键字段的配置 -->
<id property="id" column="id"></id>
<!-- 普通字段的配置 -->
<result property="names" column="name"></result>
<result property="bir" column="bir"/>
</resultMap>
resultMap属性
Type: 当前的bean对象类型(数据模型的类型)
Id: 新的类型的标记 标识
resultMap子标签
<id> 标签:主键标签,配置的主键的映射关系
resultMap: 普通字段的映射关系
typeAliases别名
别名: mapper.xml 中经常使用到bean 模型的配置,声明类型的时候,类的全部名称。多个标签重复写出。别名就是决绝多个标签重复写bean类型
Select …. From Emp_employee_info e,Dept_dept_info d where e.id=d.id;
Mybatis: 声明类的别名,在mybatis-config.xml
< typeAliases>
< typeAliase type=”类的描述” aliase=”定义名字” ></ typeAliase>
</ typeAliases>
示例
<typeAliases>
<!--
type: bean类型
alias:(StudentMessage) 类名
-->
<typeAlias type="com.study.bean.Person" alias="Person"/>
<!-- 直接扫描实体类的包 -->
<package name="beike.mybatis.pojo"/>
</typeAliases>
Mybatis: 使用类的别名,在***mapper.xml
ParameterType resultType : 属性中使用别名
JdbcType
在给sql传入参数,指定当前的参数的mybatis类型
#{变量名,jdbcType= 类型}
示例
<insert id="save" parameterType="Person">
insert into person(id, name,bir)
values (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{ bir,jdbcType=TIMESTAMP})
</insert>
大部分操作中都不会指定这个类型,mybatis会默认给我们指定当前的这个类型,开发中基本上使用的就是mybatis默认给我们的匹配类型。
总结:
Mybatis: orm框架,代替了jdbc数据持久化操作。
为什么使用mybatis放弃jdbc(面试题)
1:jdbc 代码冗余 Statement ResultSet
2:sql语句和java代码耦合在一起,不利于程序的更新扩展。
3:频繁的打开和关闭连接耗费资源(连接池,自动回收连接,连接重复利用)
4: 事务控制,setAutoCommit(false) commit rollback setAutoCommit(true),mybatis 直接将事务的处理器进行封装。