一、概述
1、mybatis是一个sql映射框架,提供了数据库操作能力
(1)sql映射(sql mapper)
将数据库中的一行数据映射为一个java对象
操作这个对象就相当于操作 表中的数据
(2)数据访问(Data Access Objects )--Dao
对数据进行增删改查
2、功能
- 提供了创建Connection,Statement,ResultSet的能力
- 提供了执行sql,将sql结果转换成对象,封装到list集合的能力
开发人员只需要提供sql语句,mybatis处理sql,
开发人员得到表中数据封装的list集合或java对象
- 提供了关闭资源的能力
3、与JDBC的比较
(1)JDBC缺点
JDBC代码较多,开发效率较低,
需要关注Connection,Statement,Resultset对象的创建和销毁
重复代码比较多
业务代码和数据库操作混在一起
(2)mybatis优点
开发人员只需要提供sql语句即可,其他重复代码由框架内部实现
二、映射步骤---dao层
1、定义接口类---xxxDao
声明相应的数据操作函数
public interface StudentDao{
public List<Student> SelectStudents();//查询所有学生
public int insertStudent(Student student);//增加学生
}
2、实现接口----xxxDao.xml
具体实现接口类中声明的函数,利用mapper标签写相应的sql语句
优点:
不需要写连接数据,通过数据库对象调用sql语句,释放资源等操作
只需要在此xml文件中,利用特定的标签符号写入需要的sql语句即可
<mapper namespace="指定要映射的dao接口类 (包名+类名)">
<select id="dao中对应方法名" resultType=“结果返回值类型”>... </select>
<update id="dao中对应方法名" resultType=“结果返回值类型”>...</update>
<insert id="dao中对应方法名" resultType=“结果返回值类型”>... </insert>
<delete id="dao中对应方法名" resultType=“结果返回值类型”>...</delete>
<mapper>
[注]一个类的全限定名称----包名+类名-----选中类,右键 copy reference即可
3、连接数据库----mybatis.xml
连接数据库,将xxxDao.xml告诉容器
<configuration>
<settings>
<!--设置mybatis全局行为:输出日志-->
<setting name="logImpl" value="STDOUT_LONGGING">
</settings>
<environments default="本工程默认连接运行的数据库">
<environment id=“自定义代表数据库名”>
<!--1、事务类型,使用jdbc中连接对象的commit和roback做事务处理-->
<transactuonManager type="JDBC"/>
<!--2、数据库连接信息-->
<dataSourece type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/真实数据库名"/>
<property name="username" value="root"/>
<property name="password" value="xxx"/>
</dataSourece>
</environment>
<environment id=“自定义代表数据库名”>
数据库2连接信息
</environment>
<!--3、指定sql映射文件位置-->
<mappers>
<mapper resource="类路径.xml"> //从类路径target/clasess开始的路径信息
</mappers>
</environments>
</configuration>
4、具体操作并获取操作结果 --xxxDaoImpl
SqlSessionFactoryBuilder---用来创建SqlSessionFactory对象
SqlSessionFactory---用来获取SqlSession
SqlSession---用来执行sql语句
(1)查
public List<Student> SelectStudents(){
//1、读取mybatis配置文件,获取数据库信息及mapper文件信息
String config="mybatis.xml";
InputStream in=Resources.getResourceAsStream(congfig);
//2、获取SqlSessionFactoryBuilder
SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
//3、获取 SqlSessionFactory
SqlSessionFactory factory=builder.build(in);
//4、获取 SqlSession
SqlSession sqlSession=factory.openSession();
//5、执行sql语句
String sqlId="sql映射文件中的namespace.select标签id值";//获取mapper文件中的sql标签语句
List<Student> students=sqlSession.selectList(sqlId);//执行查询
sqlSession.close();
//6、返回结果
return students;
}
(2)增
<1>将共有的获取SqlSession过程封装成工具类
public class MyBatisUtils{
private static SqlSessionFactory factory=null;
//SqlSessionFactory对象只用创建一次
static{
try{
//1、读取mybatis配置文件,获取数据库信息及mapper文件信息
String config="mybatis.xml";
InputStream in=Resources.getResourceAsStream(congfig);
//2、获取SqlSessionFactoryBuilder
SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
//3、获取 SqlSessionFactory
factory=builder.build(in);
}
catch(IOException e){e.printStackTrace();}
}
//4、封装函数,获取 SqlSession
public static SqlSession getSqlSession(){
SqlSession sqlSession=null;
if(factory!=null){
sqlSession=factory.openSession();
}
}
return sqlSession;
}
[注]一个对象的创建只需要一次时,则可以放在static代码块中,类加载时就执行,且只执行一次
若后面需要用到该对象,在代码块之外先声明一下,类加载时对象就会创建并赋值
<2>具体实现
public int insertStudent(Student student){
//1、获取 SqlSession
SqlSession sqlSession=MyBatisUtils.getSqlSession();
//2、执行sql语句
String sqlId="sql映射文件中的namespace.insert标签id值";//获取mapper文件中的sql标签语句
int n=sqlSession.insert(sqlId,student);
//3、提交事务和关闭资源
sqlSession.commit();
sqlSession.close();
}
5、测试 (一般用于业务层或控制层)
(1)一般方式
public class TestMybatis{
//查询
public void testSelect(){
StudentDao=new StudentDaoImpl();
List<Student> studentList=dao.SelectStudents();
for(Student stu:studentList){
System.out.println(stu);
}
}
//添加
public void testInsert(){
StudentDao=new StudentDaoImpl();
Student s=new Student();
s.setId(001);
s.setName("张三");
int n=dao.insertStudent();
System.out.println("添加对象数量"+n);
}
}
(2)动态代理方式
public class TestMybatis{
//查询
public void testSelect(){
SqlSession sqlSession=MyBatisUtils.getSqlSession();
StudentDao dao=sqlSession.getMapper(StudentDao.class);
// StudentDao=new StudentDaoImpl();
List<Student> studentList=dao.SelectStudents();
for(Student stu:studentList){
System.out.println(stu);
}
}
//添加
public void testInsert(){
SqlSession sqlSession=MyBatisUtils.getSqlSession();
StudentDao dao=sqlSession.getMapper(StudentDao.class);
Student s=new Student();
s.setId(001);
s.setName("张三");
int n=dao.insertStudent();
System.out.println("添加对象数量"+n);
}
}
三、sql映射xml文件--sql语句的编写
1、增删改查标签
<mapper namespace="指定要映射的dao接口类 (包名+类名)">
<select id="dao中对应方法名" resultType=“结果返回值类型”>... </select>
<update id="dao中对应方法名" resultType=“结果返回值类型”>...</update>
<insert id="dao中对应方法名" resultType=“结果返回值类型”>... </insert>
<delete id="dao中对应方法名" resultType=“结果返回值类型”>...</delete>
<mapper>
2、传参
(1)传入参数类型---parameterType(可省略)
用来标识待传入参数的类型
<select id="dao中对应方法名" parameterType="int" resultType=“结果返回值类型”>
select name from student where id=#{studentId}
</select>
(2)传参
【传一个参数】
#{任意字符} --占位符
使用#{}之后,mybatis执行的sql是使用jdbc中PreparedStatement对象,由mybatis内部执行
<select id="selectStudentByid" resultType=“com.entity.Student”>
select id,name,email from student where id=#{studentId}
</select>
【传两个参数】
方式一:命名参数,@Param("自定义参数名称")
<1> dao接口--命名参数
List<Student> selectMultiParam(@Param("myname")String name,
@Param("mynage")int age )
<2>dao.xml
<select id="selectMultiParam" resultType=“com.entity.Student”>
select id,name,email from student where name=#{myname} or age=#{myage}
</select>
方式二:对象传参 ,将要传入的参数封装成一个对象
<1>将要传入的参数封装成一个java对象(类),对象属性是要传入的参数
public class QueryParam{
private String myName;
private String myAge;
}
<2> dao
List<Student> selectMultiParam(QueryParam param)
<3>dao.xml
<select id="selectMultiParam" resultType=“com.entity.Student”>
select id,name,email from student where name=#{myname} or age=#{myage}
</select>
(3)占位符#和$
#特点:
- #使用?在sql语句种做占位的,使用PrepareStatement执行sql,效率高
- #能够避免sql注入,更安全
$特点:
- $采用字符串连接方式,使用Statement对象执行sql,效率低
- $有sql注入风险
- $可替换表名或列名
3、结果处理
(1) resultType
<select id="selectMultiParam" resultType=“com.entity.Student”>
</select>
(2)resultMap
- 给指定的属性赋值
- 解决数据库列名和实体类属性名不同
如,表中列名为name 属性名为stuname
<1>自定义表类不匹配的类--resultMap标签,并定义列和属性的关系,如列id,类属性sid
<resultMap id="myStudentMap" resultType=“com.entity.Student”>
<id column=" id" property=“sid”>
<result column="name" property=“sname”>
<result column="age" property=“sage”>
</resultMap >
<2>映射.
<select id="selectMultiParam" resultMap=“myStudentMap”>
</select>
4、模糊查询
<select id="selectBylike" resultType=“com.entity.Student”>
select id,name,email from student where name like #{myname}
</select>
5、控制语句---标签形式
(1)if
<select id="selectStudentif" resultType=“com.entity.Student”>
select id,name,email from student where
<if test="name!=null and name!=' ' ">
name= #{myname}
</if>
</select>
(2)where
<select id="selectStudentif" resultType=“com.entity.Student”>
select id,name,email from student
<where>
<if test="name!=null and name!=' ' ">
name= #{myname}
</if>
<where>
</select>
(3)foreach
dao:
List<Student> selectStudentFor(List<Student> stulist)
dao.xml
<select id="selectStudentFor" resultType=“com.entity.Student”>
select * from student where id in
<foreach collection"list" item="mystu" open="(" close=")" separator=",">
#{mystu.myname}
</foreach >
</select>
四、Mybatis缓存
1、一级缓存--SqlSession级别(默认开启)
- 一级缓存时SqlSession范围的:当同一个SqlSession中执行两次相同的SQL语句时,第一次执行完毕会将结果保存到缓存中,第二次查询直接从缓存中获取
- 操作数据库时需要创建SqlSession对象,对象中由一个HashMap存储缓存数据
- 不同SqlSession之间缓存数据区域互不影响
- 当SqlSession执行DML操作时,Nybatis需将缓存清空--保证数据的有效性
2、二级缓存--Mapper级别(默认关闭)
- 多个SqlSession使用同一个Mapper的SQL语句操作数据库,得到的数据存在二级缓存的HashMap中
- 多个SqlSession共用二级缓存,作用域是Mapper中的同一个namespace
- 不同SqlSession两次执行相同namespace下的SQL语句会将数据保存在二级缓存中,第二次直接从二级缓存中取出数据