一、Mybatis概述
Mybatis是java的持久层框架,对jdbc进行了封装。开发者只需要编写sql语句,而不编写jdbc的代码。
二、简单Mybatis入门
1.创建数据库以及表
2.创建maven项目,在pom文件中加载相关的依赖(mybatis的版本坐标,mysql驱动jar包,junit单元测试,log4j日志包)
<dependencies>
<!--mybatis核心包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<!--mysql驱动包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<!-- 日志 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
3.编写实体类
属性尽量使用包装类。实体类中的属性和数据库表中的属性名字和类型要一一对应。不要忘记写get、set方法
4.编写mapper接口,声明要实现的方法。
public interface UserMapper {
/**
* 查询所有的用户
* @return
*/
public List<User> findAll();
}
5.在resource文件夹下,创建配置文件usermapper.xml
namespace导入约束文件(刚才写的mapper接口)。在这里写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">
<mapper namespace="com.qcbyjy.mapper.UserMapper">
<select id="findAll" resultType="com.qcbyjy.domain.User">
select * from user;
</select>
</mapper>
说明:namespace名称空间,本配置文件写的sql是在这个声明空间声明过的。
Id=”xx”表示要实现的接口中的方法名称。resultType是返回值类型,写全路径。
6.编写主配置文件主配置文件叫“sqlmapconfig.xml”
在主配置文件中要配置连接池、事务管理类型、加载各个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>
<!-- 配置环境们 -->
<environments default="mysql">
<!-- 配置具体的环境 -->
<environment id="mysql">
<!-- 配置事务管理类型 -->
<transactionManager type="JDBC"/>
<!-- 配置是否需要使用连接池,POOLED使用,UNPOOLED不使用 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybatis_db"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- 加载映射的配置文件 -->
<mappers>
<mapper resource="mappers/UserMapper.xml"/>
</mappers>
</configuration>
7.测试
@Test
public void run2() throws Exception {
// 加载配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 构建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
// 获取到session对象
SqlSession session = factory.openSession();
// 查询所有的数据
List<User> list = session.selectList("com.qcbyjy.mapper.UserMapper.findAll");
// 变量集合
for (User user : list) {
System.out.println(user);
}
// 关闭资源
session.close();
inputStream.close();
}
}
三、增删改查mapper中sql的编写
<!-- 通过id查询 -->
<select id="findById" resultType="com.qcbyjy.domain.User" parameterType="int">
select * from user where id = #{id};
</select>
<!--保存操作-->
<insert id="insert" parameterType="com.qcbyjy.domain.User">
insert into user (username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address})
</insert>
<!-- 修改 -->
<update id="update" parameterType="com.qcbyjy.domain.User">
update user set username = #{username},birthday = #{birthday},sex = #{sex},address=#{address} where id = #{id}
</update>
<!-- 删除 -->
<delete id="delete" parameterType="Integer">
delete from user where id = #{id}
</delete>
<!-- 模糊查询 -->
<select id="findByName" resultType="com.qcbyjy.domain.User" parameterType="string">
<!-- 第一种方式的SQL语句
select * from user where username like #{username}
-->
<!-- 第二章SQL语句的编写 强调:'%${value}%'不能修改,固定写法(不推荐使用) -->
select * from user where username like '%${value}%'
</select>
1.在接收参数时#{}和${}的区别?
- #是一个占位符,如果传递基本数据类型或者String类型,名称随意。如果传递对象中的属性名称要和属性对应。#的形式编译后执行的语句参数带”” 引号,可以防止sql注入问题。
- $是字符串拼接的意思,编译后的sql语句参数位置没有””引号,可能会造成sql注入问题。使用$时如果接受基本数据类型或者String括号内只能写value,接收对象,要写属性名。
2.什么是sql注入问题?
用户提交的数据(字符串或其他数据)当作SQL语句去执行。
例如http://www.oatest.com/index.php?password=123 or 1=1即使密码错误也能访问
四、mybatis参数详解
1.parameterType:参数类型;
2.resultType:返回值类型
返回基本数据类型,String list ,也可以返回单个对象,不过对象中的属性名要和sql中的参数名一致。
<select id="findByVo" parameterType="com.qcbyjy.domain.QueryVo" resultType="com.qcbyjy.domain.User">
select * from user where username = #{user.username}
</select>
3.resultMap实质上将查询结果映射到pojo对象中,自己封装,可用于多表联查。
<resultMap id="userMap" type="com.qcbyjy.domain.User">
<!--
property="JavaBean中的属性"
column="表中的字段"
-->
<result property="id" column="_id"/>
<result property="username" column="_username" />
<result property="birthday" column="_birthday" />
<result property="sex" column="_sex" />
<result property="address" column="_address" />
</resultMap>
4.别名/简写
注意:在写全路径时例如int String路径可以简写,这是框架提供的。我们也可以在配置文件给全路编写简便写法。(起别名)
<!-- 定义别名 -->
<typeAliases>
<!-- 把com.qcbyjy.domain.User使用user别名来显示,别名user User USER都可以,默认是忽略大写的
<typeAlias type="com.qcbyjy.domain.User" alias="user"/>
-->
<!-- 针对com.qcbyjy.domain包下的所有的类,都可以使用当前的类名做为别名 -->
<package name="com.qcbyjy.domain"/>
</typeAliases>
这样在xml配置文件中就可以简写
<select id="findAll" resultType="user">
select * from user
</select>
五、MyBatis的连接池
1.连接池技术
存储一定数量的连接,每次取出一条空闲的连接。允许应用程序重复使用一个连接,而无需每次都新建连接,这样可以提高效率。
Maybatis内置了连接池技术,可以通过修改配置选择是否使用连接池。
2.MyBatis映射文件的SQL语句编写
-
动态sql的if标签
<select id="findByWhere" parameterType="com.qcbyjy.domain.User" resultType="com.qcbyjy.domain.User">
select * from user where 1 = 1
<if test="username != null and username != ''">
and username like #{username}
</if>
<if test="sex != null and sex != ''">
and sex = #{sex}
</if>
</select>
-
动态SQL语句之where标签
where标签是为了去掉where 1=1拼接,where标签使用在if标签外面。
-
动态SQL语句之foreach标签
实现:select * from user where id = 1 or id = 2 or id = 3
在User类中添加属性 private List<Integer> ids;
<!--foreach标签 select * from user where id = 1 or id = 2 or id = 3 -->
<select id="findByIds" parameterType="com.qcbyjy.domain.User" resultType="com.qcbyjy.domain.User">
select * from user
<where>
<foreach collection="ids" open="id = " separator="or id = " item="i">
#{i}
</foreach>
</where>
</select>
select * from user where id in (1,2,3)
<!--foreach标签 select * from user where id in (1,2,3)-->
<select id="findByIds" parameterType="com.qcbyjy.domain.User" resultType="com.qcbyjy.domain.User">
select * from user
<where>
<foreach collection="ids" open="id in ( " separator="," close=")" item="i">
#{i}
</foreach>
</where>
</select>
-
提取公共sql
<sql id="findAllSql">
select * from user
</sql>
<select id="findAll" resultType="com.qcbyjy.domain.User">
<include refid="findAllSql" />
</select>
六、表的关系处理
1.一对一
两张表可以设计成一张表
2.多对一
表1和表2一对一,或者表1和表2多对一。可以在表1的实体类中添加表2对应的实体类对象作为属性。表示每一个表1都只对应一个表2。
在编写sql语句时就涉及到了联查,要注意对查询结果使用resultmap封装。
<?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.qcbyjy.mapper.AccountMapper">
<!--内连接查询-->
<select id="findAll" resultMap="accountMap">
select a.*,u.username,u.address from account a,user u where a.uid = u.id
</select>
<!--进行数据封装-->
<resultMap id="accountMap" type="com.qcbyjy.domain.Account">
<result property="id" column="id" />
<result property="uid" column="uid"/>
<result property="money" column="money"/>
<association property="user" javaType="com.qcbyjy.domain.User">
<result property="username" column="username"/>
<result property="address" column="address"/>
</association>
</resultMap>
</mapper>
3.一对多
4.多对多
表1和表2一对多或者多对多。在表1中添加list集合封装表2。
例如用户和账号是一对多的关系,在用户表添加:(不要忘记添加setget方法)
mapper配置文件同样要注意查询结果的封装。
<!--一对多查询-->
<select id="findOneToMany" resultMap="userMap">
select u.*,a.money from user u left join account a on u.id = a.uid
</select>
<resultMap type="com.qcbyjy.domain.User" id="userMap">
<result property="id" column="id"/>
<result property="username" column="username"/>
<result property="birthday" column="birthday"/>
<result property="sex" column="sex"/>
<result property="address" column="address"/>
<collection property="accounts" ofType="com.qcbyjy.domain.Account">
<result property="money" column="money"/>
</collection>
</resultMap>
七、延迟加载
1.什么是延迟加载??
例子:对于用户表和账户表,存在一对多的关系。
延迟加载:当查询用户时只将用户的信息查询出来,当使用时再查询用户对应的账户信息。
立即加载:查询用户时,同时也把对应的账户信息查询到。
2.演示
Accountmapper编写方法
public List<Account> findAll();
Accountmapper.xml文件配置延迟加载
<?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.qcbyjy.mapper.AccountMapper">
<!-- 内连接的查询 -->
<select id="findAll" resultMap="accountMap">
SELECT * from account
</select>
<!-- 配置映射 -->
<resultMap type="Account" id="accountMap">
<id column="id" property="id"/>
<result column="uid" property="uid"/>
<result column="money" property="money"/>
//配置映射时,select表示调用usermapper的findbyid方法,column表示调用时传递的参数是account的uid属性
<!-- 配置延迟加载 -->
<association property="user" javaType="User" select="com.qcbyjy.mapper.UserMapper.findById" column="uid">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="birthday" property="birthday"/>
<result column="sex" property="sex"/>
<result column="addresss" property="addresss"/>
</association>
</resultMap>
</mapper>
usermapper编写方法(延迟加载调用的方法)
public User findById(Integer uid);
Usermapper.xml编写findbyid对应的sql语句。(注意使用select引)
<select id="findById" parameterType="int" resultType="User">
select * from user where id = #{id}
</select>
在sqlmapconfig.xml总配置文件开启延迟加载
<settings>
<!-- 开启延迟加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 将积极加载改为消极加载及按需加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
八、缓存
缓存:在内存中临时存放的数据,速度快,减少访问数据库的次数。
一级缓存的原理:Mybtis的一级缓存是sqlsession的缓存,sqlsession维护了一个map对象,key存放sql语句,value存放执行的结果集。
查询时先从sqlsession中寻找,如果有直接返回,没有再去数据库中查询。
一级缓存的声明周期和sqlsession的生命周期一致,sqlsession对象关闭,一级缓存也关闭。