1.使用mybatis的操作步骤--
1.1Mybatis核心配置以及映射配置文件
<!--在maven项目下导入mybatis的jar包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.4</version>
</dependency>
<!--mybatis的xml配置方式:需要在resources的目录创建xml文件配置mybatis的核心配置文件-->
<!--头部文件-->
<?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>
<!--环境配置-->
<!--需要连接mysql 给default属性设置一个标识-->
<environments default="msyql">
<!--id和上面default一致-->
<environment id="msyql">
<!--事务管理器:Jdbc控制事务-->
<transactionManager type="JDBC"/>
<!--配置数据源mybatis里面涉及三种数据源
mybaits自带连接池 POOLED
不用自带的连接池 UNPOOLED
JNDI(web相关的一种连接池)
-->
<dataSource type="org.apache.ibatis.datasource.pooled.PooledDataSourceFactory">
<!--配置数据源的一些属性,连接数据库的信息-->
<!--配置驱动类-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<!--配置url-->
<property name="url" value="jdbc:mysql://localhost:3306/myee_2113?characterEncoding=utf8"/>
<!--配置用户名-->
<property name="username" value="root"/>
<!--配置密码-->
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--当读取SqlMapConfig.xml文件的时候,需要加载映射文件xxxMapper.xml-->
<!--配置映射器-->
<mappers>
<mapper resource="com/qf/mapper/UserMapper.xml"></mapper>
</mappers>
</configuration>
1.2定义mapper接口
//定义mapper接口(相当于之间xxxDao:数据访问接口)
/*查询所有用户*/
List<User> findAllUser() ;
1.3配置映射文件
<!--在resources资源路径下配置xxxMapper对应的 xxxMapper.xml (sql映射文件)-->
<!--头部文件-->
<?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:名称空间-->
<mapper namespace="com.qf.mapper.UserMapper">
<!--查询所有用户列表-->
<!--id:和接口中的方法名要一致: 才能定位到具体的方法上
parameterType:指定的是输入映射参数和当前接口中的方法的参数类型一致
如果int,书写java.lang.Integer/Integer...
如果String.书写java.lang.String/String
resultType:输出映射参数
返回的List :需要返回的list集合中泛型的类型的全限定名称
返回字符串,输入映射:String,java.lang.String
-->
<select id="findAllUser" resultType="com.qf.pojo.User">
select * from user
</select>
</mapper>
1.3测试类
public class MyBatisTest {
InputStream inputStream ;
SqlSession sqlSession ;
StudentMapper studentMapper ;//接口对象声明
@Before
public void init() throws Exception {
//1)驱动mybatis核心配置文件
inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactoryBuilder构造者设计模式
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder() ;
//通过加载资源文件输入流,获取SqlSessionFactory接口工厂
SqlSessionFactory sqlSessionFactory = builder.build(inputStream);
//创建执行对象
sqlSession = sqlSessionFactory.openSession();//开启手动提交
//获取接口代理对象
studentMapper = sqlSession.getMapper(StudentMapper.class) ;
}
//测试查询所有的学生
@Test
public void testFindAll(){
List<Student> list = studentMapper.findAll();
if(list!=null){
for(Student student:list){
System.out.println(student);
}
}
}
}
2.mybatis插入数据,获取自增长主键id的值
mybatis插入数据的时候,获取表中自增长主键id的值
insert标签中有子标签seletkey,属性如下:
keyProperty:实体类中的属性值 (通过id字段要和表中id字段映射)
keyColumn:表中的主键字段 id字段
order:什么时候执行 sekectKey标签中的语句
AFTER 在执行插入之后,执行selectkey的语句,获取最后一次自增长主键的id值
SELECT LAST_INSERT_ID()
BEFORE: 插入数据之前执行
resultType:获取到的自增长主键的类型 int
<!--在执行插入之后,执行语句,获取最后的自增长主键id的值-->
<insert id="addStudent" parameterType="com.qf.pojo.Student">
<selectKey keyProperty="id" keyColumn="id" order="AFTER" resultType="int">
SELECT LAST_INSERT_ID()
</selectKey>
insert into student(name,age,address,birthday) values(#{name},#{age},#{address},#{birthday})
</insert>
3.1封装vo实体类
//包装的实体类--里面包含的一个学生类
public class QueryVo {
private Student student ;
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
}
3.2mybatis基本模糊查询
<!--模糊查询学生列表-->
<select id="findStudentByName" resultType="student">
<!-- mybaits固定属性‘%${value}%’
${} :字符串拼接符号,值和 % %之间进行拼接
mybatis开发中,不要使用这种符号,尽量去使用#{},而不是用${},这也是sql的一种
-->
<!-- select * from student where name like '%${value}%' -->
<!--使用#{}推荐-->
select * from student where name like #{name}
</select>
3.3封装的vo实体来模糊查询学生列表
<select id="findUserByQueryVo" resultType="student" parameterType="queryvo">
<!--QueryVo类型包含的是Student类型,访问的时候可以 queryvo对象.getStudent().getName()
对象图导航语言 简写书写格式 将get()去掉
student是QueryVo的bean属性
name又是学生对象的bean属性
可以简写为:#{student.name}
-->
select * from student where name like #{student.name}
</select>
4.传统dao的弊端
1)开发过程还需要核心配置文件,也需要映射文件,代码大量加大,还需要提供接口实现类
2)从内存角度考虑:以后需要在业务层需要频繁的数据访问接口,不断的开辟堆内存空间;
3)开发中遵循"低耦合,高内聚",而传统dao的程序之间出现耦合性,而降低耦合性经常使用的技术"反射技术";
mapper代理的方式:使用到了jdk动态代理,就比这种传统方式优秀!
5.mybatis注解开发流程
<!--注解开发,不需要加载 映射文件,class属性直接指定接口的全限定名称-->
<mapper>
<mapper class="com.qf.mapper.StudentMapper"></mapper>
</mapper>
//StudentMapper
@Select("select * from student")
//@Select注解:查询的---替代了xx.xml映射文件中的select标签
List<Student> findAll() ;
@Delete("delete from student where id = #{id}") //代替映射文件中的delete标签
void deleteStudent(int id) ;
@Update("update student set name = #{name},age = #{age},address = #{address},birthday = #{birthday} where id = #{id}) //代替update标签
void updateStudentById(Student student) ;
@Insert("insert into student(name,age,address,birthday) values(#{name},#{age},#{address},#{birthday})) //代替了insert标签
void addStudent(Student student) ;
6.读取外部配置文件,获取jdbc连接信息以及加入实体类包扫描
<!--别名的包扫描,它直接将实体所在包指定,别名默认就是当前类名小写,(一般不区分大小写)-->
<typeAliases>
<package name="com.qf.pojo"/>
</typeAliases>
<!--属性配置,加载类路径下的其他properties配置文件
属性:resource="指定资源目录下的配置文件名称"-->
<properties resource="jdbc.properties"/>
<!--value:通过${获取配置文件中的key对应的value}-->
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
<!--mapper的别名包扫描的方式-->
<!--将包内的映射器接口实现全部注册为映射器,因为映射文件和接口的包结构一致,自动扫描-->
<mappers>
<package name="com.qf.mapper"/>
</mappers>
7.mybatis的原理
架构体现:
1)准备核心配置文件 mybatis-Config.xml---->mybatis的Resources就来读取配置文件的内容
2)将配置文件内容---->每一个标签--->封装到一个类中,作为它的属性:Configuration类(配置类)
3)加载映射器 Mappers -->里面配置的mapper的sql映射文件---->MapperRegister:Mapper注册器
Configuration类(配置类):
//创建SqlSessionFactoryBuilder--->构建者,就是将资源输入流的内容,封装Configuration类
//创建SqlSessionFactory接口工厂------>通过子实现类 DefaultSqlSessionFactory进行创建
4)创建SqlSesison:执行对象---->底层有接口Executor执行器 ----->最终就是创建一个PreparedStatement:预编译对象
5)T <T> getMapper(Class<T> class):---->mapper代理底层就是一个jdk动态代理,针对XXXMapper接口 产生代理对象(jdk动态代理前提基于接口实现)--->MapperProxy implements InvocationHandler
8.mybatis的参数绑定
//@Param("将指定的参数绑定到这个注解中,起一个名称")
//按照学生姓名和地址查询学生信息
Student findStudentByNameAndAddress(@Param("name") String name,@Param("addr") String address) ;
//参数绑定的使用
<select id="findStudentByNameAndAddress"
resultType="student">
select * from student where name = #{name} and
address = #{addr}
</select>
9.参数为复杂类型的Map集合
<!--Student findStudentByNameAndBirthday(Map values) ;-->
<select id="findStudentByNameAndAddress"resultType="student">
select * from student where name = #{name} and
address = #{birthday}
</select>
<!--测试-->
//创建Map集合
Map map = new HashMap<>() ;
//给映射文件中的参数进行赋值
map.put("name","刘桑") ;
map.put("birthday","1996-12-10 00:00:00") ;
10.连接池的特点
连接池的特点:
创建一些固定的可重用的连接对象,重复利用它,当某个连接对象被某个持有的线程使用完毕之后,然后归还连接池中.
11.mybatis启用德鲁伊的连接池
1)导包
<dependency>
<!--导入阿里的德鲁伊 druid 连接池-->
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.13</version>
</dependency>
2)配置文件:使用自己的连接池:自定义一个工厂类 继承了 mybatis里面的PooledDataSourceFactory
<dataSource type="com.qf.datasource.MyDruidDataSourceFactory">
<property name="driverClass" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!--最大激活数量-->
<property name="maxActive" value="${jdbc.maxActive}"/>
</dataSource>
3)自定义这个类继承自mybatis的连接池数据源工厂类
public class MyDruidDataSourceFactory extends
PooledDataSourceFactory {
//构造方法
public MyDruidDataSourceFactory(){
//创建德鲁伊的数据源对象
this.dataSource = new DruidDataSource() ;
}
}
12.mybatis的高级映射resultMap
使用场景:
1)当实体类属性和字段一样
2)mybatis多表查询的时候可以用
使用步骤:
首先在映射文件中定义resultMap,然后在具体的增删改,查询语句中将reusltMap引入,resultMap里面就是可以将每一个字段和实体类的属性一一映射
12.1 定义resultMaop
<!-- 定义resultMap
id:resultMap它的标识id,不可以重复;
type:就是实体类的全限定名称/别名 (返回值类型)
-->
<resultMap id="myMap" type="student">
<!--配置主键字段: 表中主键字段 id 和 实体类的属性 id一致
property:实体类的属性名称 stuId
column:表中字段列的名称 主键id
-->
<id property="stuId" column="id"></id>
<!--普通字段和实体类的其他属性名称一一对应-->
<result property="stuName" column="name"></result>
<result property="stuAge" column="age"></result>
<result property="stuAddress" column="address"></result>
<result property="stuBirthday" column="birthday"></result>
</resultMap>
<!--引入resultMap 引入上面id属性值 -->
<select id="findAll" resultMap="myMap">
select * from student
</select>
13.动态sql语句---where
<select id="findStudentByConditon" resultMap="myMap">
select * from student
<!---利用where标签来代替where关键字-->
<where>
<!--
此时后面的条件利用if标签进行判断 当前这些属性不为null的时候才能查询
test属性:判断当前实体类型的属性是否满足条件,true还是false,true则执行, 否则不执行-->
<if test="stuName!=null">
name = #{stuName}
</if>
<if test="stuAddress!=null">
and address = #{stuAddress}
</if>
</where>
</select>
14.动态sql片段
动态的sql片段将重复性的sql抽取出来,在其他sql中引入这个sql片段即可
<sql id="mySelectSql">
select * from student
</sql>
<select id="findAll" resultMap="myMap">
<!--引入sql片段 refid:引入sql片段指定的id值 -->
<include refid="mySelectSql"/>
</select>
15.动态aql--for each遍历数据
<select id="findStudentByVO" parameterType="queryvo" resultMap="myMap">
<!--引入sql片段-->
<include refid="mySelectSql"/>
<where>
<!--foreach标签属性
collection:当前实体类中封装的集合属性名称
open:使用子查询 in(x,x,x) 以什么格式开始查询
separator:分割符号:,隔开
close:以什么格式结束:")"
item:循环遍历过程中的变量名称
foreach中间的内容:#{item里面指定的变量名称} -->
<foreach collection="ids" open=" id in(" separator="," close=")"
item="id">
#{id}
</foreach>
</where>
</select>