jar包,加入到项目classpath中
一个mybatis.jar;一个mysql-connector-java.jar
一种是映射文件(mapper),一种是主配置文件(主要是数据库连接等信息,以及加载mapper文件)。
<mapper namespace="com.yunsi.pojo.User">
<select id="getUsers" resultType="com.yunsi.pojo.User">
select username,password from t_login
select>
mapper>
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/yunsi"/>
<property name="username" value="root"/>
<property name="password" value="test"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="com/yunsi/pojo/UserMapper.xml"/>
mappers>
selectOne获取一个对象
selectList获取一堆对象(多行)
update
delete
insert
close
SqlSession的操作,虽说是底层是jdbc,可以它的所有方法不会报SQLException,而是把SQLException转换成了运行时异常。
public static void main(String[] args) {
//mybatis的api(操纵数据库)
//1.读取主配置文件(使用SqlSessionFactoryBuilder)
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//2.返回读取的结果(SqlSessionFactory)
InputStream inputStream = Test1.class.getResourceAsStream("/mybatis-config.xml");
SqlSessionFactory factory = builder.build(inputStream);
//3.获取SqlSession对象(后续增删改查数据库都是通过它来完成的)
SqlSession session = factory.openSession();
List<User> usersList = session.selectList("getUsers");
for(User user : usersList) {
System.out.println(user.getUsername()+" "+user.getPassword());
}
//4.关闭资源(对比jdbc,就容易多了)
session.close();
}
查询数据库时,需要以查询结果为查询条件进行关联查询。
在mybatis中通过association标签和collection标签实现子查询。
collection用于一对多关系,association用于一对一和多对一。
public class User{
private Card card_one; //一对一,映射时使用association
private List<Card> card_many; //一对多,映射时使用collection
}
<collection property="实体类属性名"
ofType="包名.实体类名"
column="{传入参数名1 = 对应的数据表名称, ...}"
select="子查询ID"
javaType="java.util.ArrayList" />
mybatis实现部门树结构查询,子查询使用和父查询一样的resultMap,递归查询子部门。
组织结构:
<resultMap id="departmentTreeMap" type="com.cdqd.app.entity.DepartmentEntity">
<id column="department_id" property="departmentId" jdbcType="INTEGER" />
<result column="department_name" property="departmentName" jdbcType="VARCHAR" />
<collection property="children"
ofType="com.cdqd.app.entity.DepartmentEntity"
column="{departmentId = department_id}"
select="selectWithLeader"
javaType="java.util.ArrayList" />
</resultMap>
第一级部门:
<select id="selectWithChildren" resultMap="departmentTreeMap" parameterType="java.util.HashMap">
select
d.*,
u.nick_name,
u.user_name,
u.user_tel
from department d
left join user_info u on d.leader_id = u.user_id
<where>
d.department_status != 2
<!--department_level = 0时为公司,不显示,从公司直属部门开始查询-->
<if test="startDepartmentId == null">
and d.department_level = 1
</if>
<if test="startDepartmentId != null">
and d.department_id = #{startDepartmentId, jdbcType = INTEGER}
</if>
</where>
</select>
子部门查询:
<select id="selectWithLeader" resultMap="departmentTreeMap">
select
d.*,
u.nick_name,
u.user_name,
u.user_tel
from department d
left join user_info u on d.leader_id = u.user_id
<where>
d.department_status != 2
<if test="departmentId != null">
and d.parent_id = #{departmentId}
</if>
</where>
</select>
<insert id=”saveUser” parameterType=”com.yunsi.pojo.User”>
insert into t_login(username,password)
values(#{username},#{pass})
insert>
<update id="updateUser">
update t_login set password=#{pass} where username=#{username}
update>
<delete id="deleteUser">
delete from t_login where username=#{username}
delete>
mybatis中使用了日志框架(log4j)记录了内部执行的状况(步骤),我们只需要“打开”日志开关就可以。
对于log4j的配置,主要有2个步骤:
数据库中标语表之间的关系,可以分成如下3种,多对一(一对多),多对多,一对一这三种。
那么mybatis对于这个问题,它是如何处理的?把数据库中的关系转成java对象之间的关系,就是一个类型中定义另一个类型的属性,至于这个属性是单个对象还是多个对象的问题。
后面的例子使用一套多对一来演示。表就是用学生表和班级表。
java中组织关系-就是通过属性
对多的一方中标记中的子标记
一的一方中标记中的子标记
它是标记中的子标记,它的作用就是类似java中的变量,可以被多次使用。例子:查询所有学生,还有一个查询按照主键列(学号)查询某个学生。大家在编写sql语句的时候,可以看到sql几乎差不多,不同的地方就是where子句。
我们之前使用过标记,它的作用就是添加一条记录,返回一个int型数据(表示添加的行数)。
假设:班级表(主键列是自增长的),学生表外检(班级编号)引用班级表主键列。业务需求是这样,添加班级这一瞬间,随后添加一位同学。添加同学的时候,如何处理学生表中的这个外键列的值(班级编号)。
mybatis另一个强大的功能就是动态sql(继获取关联对象之后有一个重要的技术),所谓的动态sql就是sql语句中某些部分是可变的,例如where子句中的信息。
标记的使用,上一个例子中的分支判断的使用,里面有一个小问题,就是重复编写where关键字
其实可以使用标记消除上面片段中的where关键字。
消除之后的结果如下:
之前使用可以看出还有一个不足,就是分支有多余现象,请同学改进一下,改进的过程中会碰到where 后面跟随者or关键字这种情形,其实这个问题的出现,正好体现出标记的另一个价值,它可以检测where之后是否有多余的or或者and关键字,一旦有,就会替我们删除它们。
标签使用在update语句中,它的一个基本作用就是变成set关键字(这一点与标签变成where关键字一样),看下面示例:
演示之后得出结论:有2个功能,一个会生成set关键字,另一个功能,会根据后面逗号是否多余,而进行删除。
这个标记的作用,就是循环拼接sql片段。什么情况下会用到循环拼接sql片段?
例子:当我们执行删除的时候,语句会这样写
delete from student where stuid=#{value}
以上这个语句满足删除任意一个学生的需求,可以如果有这样的需求该如何?
一次性删除大量的学生,如果还是上面的sql语句,那么java代码会如下这样:
@Test
public void test(){
SqlSession session = ...
String[] stuids = {“1”,”2”,”3”.....};
for(String stuid : stuids){
session.delete(“deleteStudentByStuid”,stuid);
}
session.commit();
session.close();
}
以上的做法正确没问题,可是性能不好。了解有这样的sql之后,应该知道如何改进。
delete from student where stuid in(1,2,3,4,…)
标记往大了说,在完成批量操作(批量删除,批量添加)上面还可以贡献一份力
批量操作:SqlSessionFactory
SqlSession openSession(ExecutorType)
ExecutorType:
分页操作,在web开发过程中,还是挺常用的,而在jdbc访问数据库的时候,分页操作,大致有2种方式,一种在内存中分页,还有一种直接查询当前页需要的数据(数据库内部分页),对于前一种方式,停留在理论阶段(学习)都是可以,生产中不能采取这种分页方式(生产中表中数据很多,一旦全部抓取到内存中,内存会奔溃),通常都是采取后一种方式,而采取后一种方式(精髓)就是能定位多少行到多少行记录,对于这个要求,不同的数据库采取的方式是不一样的,例如:mysql中使用关键字limit,oracle中采用2层子查询嵌套的方式搭配rownum(伪列)
其实就是针对不同的数据库,在mapper文件中编写相对应的sql语句。不过除了分页的sql语句之外,我们还需要一个辅助的sql,这条语句专门负责查询表中行的数量,以便计算分页中需要用到的信息。
pagehelper
使用步骤:
缓存这个技术,就是可以减少查询次数,把查询出来的信息暂时存储在内存(或者磁盘),等待下一次查询的时候,我们可以从缓存中获取,从而避免再次从数据库中查询。(减少数据库访问次数)
缓存积极的一面就是提高查询效率(有些时候,并没有查询数据库,而是从缓存中获取数据),不足的一面,就是缓存中的数据可能是过期的。
延迟加载,当查询的时候,涉及到关联对象(多对一,一对一)一的一端,先前我们随着查询基本信息的发生,一也会被查询出来(单独一个查询),(多对多)多的一端,我们查询基本信息的时候,多的一端也会发送sql查询。
配置方式:
mybatis有一级缓存和二级缓存区分,默认一级缓存是开启的,二级缓存是关闭(可以通过手动开启)。
这边所说的一级缓存,其实就是SqlSession,原来一级缓存就在SqlSession内部。
原来我们使用mybatis是这样:session.update(“updateStudent”,stu); session.selectList(“getStudents”)
以上这样的访问方式由一个问题,就是java程序在编译的时候,并不能对立面的sql逻辑名称做有效的检查。(万一手误大小写打错了或者漏打了,都会导致运行的时候出现错误)
mybatis在这个问题上,又提供了一个有效的解决方法,原理:它把所有的sql逻辑名称全部映射到java中的一个接口中的方法名称上面,以至于我们实际调用的时候,都是针对接口中的方法进行编程,这样一来,就避免了名称敲错了,漏写了等情形。
具体做法: