Mybatis
Mybatis是一个支持普通SQL查询,存储过程和高级映射的持久层框架。
Mybatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装。
Mybatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的pojo映射成数据库的记录。
- 简单介绍
1.mybatis-config.xml
在该xml文件中配置连接数据库的一些信息,如数据库驱动(driver),路径(url),账号密码等。该文件一般处于项目最外层。
之后将该xml文件作为resource来一步步实例化SqlSession。
<typeAliases>别名标签下,定义<package name="pojo包路径">该包下的pojo类型可以在写resultType时直接写类名而不用写全限定名。
<mappers>下<mapper resource="路径">用来注册mapper.xml。
2.接下来,应该有一个pojo的包(也可以说是model层。)里面还有pojo类。
pojo对象主要是自己想要读取的内容,将其封装成一个对象,到时候在读取时再将数据库中读取到的内容映射到该类的属性变量中。写好pojo类的属性,自动生成get()set()方法,按情况重写toString()equal()hashCode()方法。
3.然后,需要一个dao层,一般一个pojo对应一个mapper。在dao层里,写mapper.xml和mapper接口。
4.然后,可以在需要访问数据的地方,通过config.xml一步步构建SqlSession,然后获得mapper接口的实例,再用其执行定义好的方法来完成SQL语句执行。
- 常用对象:
1.SqlSessionFactory
SqlSessionFactory的实例可以通过SqlSessionFactoryBuilder获得,而SqlSessionFactoryBuilder则可以从xml配置文件或一个预先定制的Configuration的实例构建出SqlSessionFactory的实例。
从xml文件构建SqlSessionFactory的实例,一般按如下形式:
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSessionFactory用来获得SqlSession实例。
2.SqlSession
SqlSession完全包含了面向数据库执行SQL命令所需的所有方法,可以通过SqlSession实例来执行已映射的SQL语句,也可以通过SqlSession获得mapper接口的实例,然后用该实例来执行SQL方法。
最常用的形式:
SqlSession session = sqlSessionFactory.openSession();
//直接执行
session.selectOne("全限名.方法名",参数)
//实例化mapper
session.getMapper(全限名.class)
使用完SqlSession对象,要调用close()方法将其关闭
- 使用xml写简单的CURD
在<mapper>里,最好写namespace,为该mapper的全限名。mapper.xml和mapper接口是同一个较好。
<mapper>下,即<select><insert><update><delete>标签,
1.查找单pojo,自己传参,用@param注解。
假设数据库有表:
product_(int id,varchar(20) name)
pojo对象:
Product(int id,String name)
写查询语句:
//ProductMapper.xml<1>
<select id="selectById" resultType="Product">
select * from product_ where id = #{id}
</select>
//ProductMapper.java
public Product selectById(@param("id") int id);
//test.java
Product p = mapper.selectById(10);
//如果使用#{0}、#{1},则不需要@param注解,#{0}对应第一个参数,依次类推。
2.查找单pojo,用parameterType传对象。
数据库、pojo同上
写查询语句:
//ProductMapper.xml<1>
<select id="selectById" parameterType="Product" resultType="Product">
select * from product_ where id = #{id}
</select>
//ProductMapper.java
public Product selectById(Product product);
//test.java
Product p1 = new Product(); p1.setId(10);
Product p2 = mapper.selectById(p1);
//根据传入Product对象,自动取得其id。
3.一对一查询
一对一类似:一个班级只由一个老师负责。一个老师只对应他的那个班级。
则该类数据存储在数据表中的形式应该为:
classes_(int cid,varchar(20) name,int tid)
teacher_(int tid,varchar(20) name,int cid)
pojo对象应该如下定义:
class Classes
{
int cid;
String name;
Teacher teacher;
}
class Teacher
{
int tid;
String name;
Classes classes;
}//省略set/get
mapper.xml写sql:
<resultMap type="(包路径.)Classes" id="ClassesBean">
<id column="cid" property="id"/>
<result column="cname" property="name"/>
<association javaType="(包路径.)Teacher property="teacher">
<id column="tid" property="id"/>
<result column="tname" property="name"/>
</association>
</resultMap>
<select id="listClasses" resultMap="ClassesBean">
select c.*,p.* , 'c.cid' cid,'c.name' cname,'t.tid' tid,'t.name' tname
from classes_ c ,teacher_ t
where c.cid = t.cid
</select>
实际上,一对一和多对一种,可以理解为一个类包含另一个类的对象。然后在resultMap中作字段名与属性名的映射。在查询语句中,则要把需要的数据都查找出来。
<resultMap>中,type为对应的pojo类全限名。id为唯一标识该resultMap的值,在之后的sql返回参数resultMap中设定。
<id>为数据表中主键对应的标签,和<result>差不多,关键是之后的属性,column对应查询字段值,property对应pojo中的属性值。
<association>用来关联,javaType标识该类全限定名,property一样为pojo相应属性值。
4.一对多,多对一
模型可以理解成,一个班有多个学生,多个学生对应一个班。
数据存储在数据表中的形式应该为:
classes_(int id,varchar(20) name);
student_(int id,varchar(20) name,int cid);
pojo对象应该定义如下:
class Classes
{
int id;
String name;
List<Student> student;
}
class Student
{
int id;
String name;
Classes classes;
}
ClassesMapper.xml:
<resultMap type="(包路径.)Classes" id="ClassesBean">
<id column="cid" property="id"/>
<result column="cname" property="name"/>
<collection ofType="(包路径.)Student" property="student">
<id column="sid" property="id"/>
<result column="sname" property="name"/>
</collection>
</resultMap>
<select id="listClasses" resultMap="ClassesBean">
select c.*,s.* c.id cid,c.name cname,s.id sid,s.name sname
from classes_ c , student_ s
where c.id = s.cid
</select>
StudentMapper.xml的写法即多对一的写法,和一对一类似。
5.多对多。
模型:一个学生可以加入多个小组,一个小组可以有多个学生。
数据存储形式:
Student_(int id,varchar(20) name);
Group_(int id,varchar(20) name);
Join(int sid,int gid,int price);
pojo定义:
class Student
{
int id;
String name;
List<Join> join;
}
class Group
{
int id;
String name;
List<Join> join;
}
class Join
{
int sid;
int gid;
int price;
}
StudentMapper.xml和GroupMapper.xml类似
<resultMap type="(包路径.)Group" id="GroupBean">
<id column="gid" property="id"/>
<result column="gname" property="name"/>
<collection ofType="(包路径.)Join" property="join">
<result column="price" property="price"/<
<association javaType="(包路径.)Student property="student">
<id column="sid" property="id"/>
<result column="sname" property="name"/>
</association>
</collection>
</resultMap>
<select id="listGroup" resultMap="GroupBean">
select s.*,g.*,j.* s.id 'sid',s.name 'sname',g.id 'gid',g.name 'gname'
from student_ s,group_ g,join_ j
where s.id = j.sid and g.id = j.gid
</select>
//取出List<Group>后
for(Group g:gl)
{
int gid = g.getId(); String gname=g.getName();
List<Join> jl = g.getJoin();
for(Join j : jl)
{
int price = j.getPrice();
List<Student> sl = j.getStudent();
for(Student s : sl)
{
int sid = s.getId(); String sname = s.getName();
}
}
}
- 动态SQL
1.<if>
一般可以用来增加条件。如:当有某个参数时,按照这个参数进行某种条件筛选。
<if test="id!=null(类似表达式)">表示#{id}不为空时
where id > #{id}
</if>
2.<where>
如果要写多个<if>时,每个语句都写where,就不能叠加,会造成愈发错误。而一个写where另一个写and追加条件,又会造成只满足and那个<if>时语法错误。如:
<if test="name!=null">
where name like concat('%',#{name},'%')
</if>
<if test="price!=0">
and price > #{price}
</if>
所以这种情况,可以用<where>
<where>
<if test="id!=null>
and id > #{id}
</if>
<if test="name!=null>
and name like concat('%',#{name},'%')
</if>
</where>
如果两个条件都不满足,会自动去掉<where>
3.<set>与<where>类似,在update中,也会碰到多字段问题。这种情况可以使用<set>
<set>
<if test="name != null">name=#{name},</if>
<if test="price != null">price=#{price}</if>
</set>
4.<choose>,<when>,<otherwise>达到if-else效果
<where>
<choose>
<when test="name != null">
and name like concat('%',#{name},'%')
</when>
<when test="price !=null and price != 0">
and price > #{price}
</when>
<otherwise>
and id >1
</otherwise>
</choose>
</where>
多条件达成时,只会选择最先达成的条件执行接下来的语句。
5.
<foreach>标签通常用在in这样的语句中。
<bind>像是再做一次字符串拼接,方便后续使用。如<bing name="likename" value= " '%'+name+'%' "
- Mybatis注解
1.简单的sql语句,可以直接写成注解形式。如:
@Select("select * from student_")
public List<Student> listStudent();
@Update("update student on name = #{name} where id = #{id}")
public int updateStudent(@Param("name") String name,@Param("id") int id);
@Insert("insert into student_ (name) values (#{name}) ")
public int addStudent(Student student);
@Delete("delete from student_ where id = #{0}")
public void deleteStudent(int id);
2.@Results和@Result类似在xml中写resultMap,作用仍是用来确定字段与属性名的映射关系。
而在一对多和多对一的情况下,可以使用@Many和@One注解,关联其他表进行查询。可以用column传参。
3.动态SQL的注释用法。
需要新加一个 SqlProvide类,写好方法后,再用@InsertProvider之类的标签。
- Tips:
1.<sql id=""></sql><include refid="">代码块,用来代码重用
2.limit用来分页
- Ques:
1.#{]和${}的区别是什么
#{}是预编译处理,${}是字符串替换。
Mybatis在处理#{}时,会将sql中的#{}替换为?,调用PreparedStatement的set方法来赋值。
Mybatis在处理${}时,就是把${}替换成变量值。
#{}防止sql注入,安全性高。
2.实体类中的属性名和表中的字段名不一样时:
<1>通过在查询的sql中定义字段名的别名,让字段名的别名和实体类的属性名一样。
<2>通过<resultMap>来映射字段名和实体类属性名的一一对应关系。(column和property)
3.通常一个xml映射文件与一个Dao接口对应。Dao工作原理:
Dao接口,就是人们常说的Mapper接口,接口的全限名,就是映射文件中的namespace的值,接口的方法名,就是映射文件中MappedStatement的id值,接口方法内的参数,就是传递给sql的参数。
Mapper接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为key值,可唯一定位一个MappedStatement
在Mybatis中,每一个<select>、<insert>、<update>、<delete>标签,都会被解析为一个MappedStatement对象。
- Point++
1.分页rowBounds
2.缓存
3.日志