java 是最全面成熟的语言,它的思想可以扩展到以后学习的任何编程语言
1,mybatis
持久层,解决jdbc的繁琐,
--1,dome
创建maven项目,导入org.mybatis jar包
.1 ,配置mybatis-config.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核心配置文件-->
<properties resource="db.properties">
<!--引入外部配置文件
编写一个配置文件
db.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis? useSSL=true&useUnicode=true&characterEncoding=UTF-8
username=root
password=123456
-->
<property name=
"username" value="root"/>
<property name="pwd" value="11111"/>
</properties>
<typeAliases>
<!--可以给实体类起别名-->
可以在实体类上用注解起别名 更方便
@Alias("user")
public class User {}
<typeAlias type="com.kuang.pojo.User" alias="User"/>
</typeAliases>
<typeAliases>
整个com.kuang.pojo包下的所有实体类默认为首字母小写别名
<package name="com.kuang.pojo"/>
</typeAliases>
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/> Mybatis默认的事务管理器就是 JDBC ,
<dataSource type="POOLED"> Mybatis默认的资源管理器 连接池 : POOLED
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--每一个Mapper.XML都需要在Mybatis核心配置文件中注册!-->
<mappers>
<mapper resource="com/kuang/dao/UserMapper.xml"/>
mapper属性
class="com.kuang.dao.UserMapper" 也可以是对应接口 条件 接口和他的Mapper配置文件必须同名!
接口和他的Mapper配置文件必须在同一个包下
</mappers>
</configuration>
@
.2 ,编写mybatis工具类
@ 获取sqlSessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
@ 获取数据库连接对象
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession(); }
.3 编写数据库对应的实体类
package com.kuang.pojo;
//实体类
public class User {
private int id;
private String name;
private String pwd;
public User() {
}
public User(int id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
}
.4 编写接口,声明对应的增删改查方法
public interface UserDao {
List<User> getUserList();
}
.5 编写接口对应的mapper.xml 配置对应的增删改查方法 一个实体类接口对应一个 mapper.xml文件 并且一定要到mybaits-config.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">
<!--namespace=绑定一个对应的Dao/Mapper接口-->
<mapper namespace="com.kuang.dao.UserDao">
<!--select查询语句-->
<select id="getUserList" resultType="com.kuang.pojo.User">
<!--select属性解析
id="getUserList" 一定和接口的方法名对应,
resultType="com.kuang.pojo.User" sql执行返回结果一般对应一个实体类
parameterType,参数如果就一个且是基本数据类型,就不用指定,会自动推断。
resultMap="UserMap" 遇到实体类属性名于数据库表字段名不一致 resultMap结果集映射
复杂的参数建议用map(万能)字段名要和key名一致
<insert id="addUser" parameterType="map">
insert into mybatis.user (id, pwd) values (#{userid},#{passWord});
</insert>
如果是对象类型,在拼接数据库语句时,字段名要和类的属性名一致
<insert id="addUser" parameterType="com.kuang.pojo.User">
insert into mybatis.user (id, name, pwd) values (#{id},#{name},#{pwd});
</insert>
模糊查询
Java代码执行的时候,传递通配符 % %
List<User> userList = mapper.getUserLike("%李%");这种做法通常比较安全
<insert id="selectUser" parameterType="String">
select * from mybatis.user where name like #{value}
</insert>
-->
select * from mybatis.user
遇到实体类属性名于数据库表字段名不一致
1,sql语句起别名
<select id="getUserById" resultType="com.kuang.pojo.User">
select id,name,pwd as password from mybatis.user where id = #{id}
</select>
2,resultMap结果集映射
<select id="getUserById" resultMap="UserMap">
select * from mybatis.user where id = #{id}
</select>
</select>
<!--结果集映射-->
<resultMap id="UserMap" type="User">
<!--column数据库中的字段,property实体类中的属性-->
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="pwd" property="password"/>
</resultMap>
</mapper>
.6 测试功能
@Test
public void test(){
//第一步:获得SqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
//方式一:getMapper
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<User> userList = userDao.getUserList();
for (User user : userList) {
System.out.println(user);
}
//关闭SqlSession
sqlSession.close();
}
2,面向注解开发 框架之重点 ,不仅仅是mybatis 其他框架也是
.1 接口上实现
@Select("select * from user")
List<User> getUsers();
// 方法存在多个参数,所有的参数前面必须加上 @Param("id")注解
关于@Param() 注解
基本类型的参数或者String类型,需要加上
引用类型不需要加
如果只有一个基本类型的话,可以忽略,但是建议大家都加上!
我们在SQL中引用的就是我们这里的 @Param() 中设定的属性名!
@Select("select * from user where id = #{id}")
User getUserByID(@Param("id") int id);
@Insert("insert into user(id,name,pwd) values (#{id},#{name},#{password})")
int addUser(User user);
@Update("update user set name=#{name},pwd=#{password} where id = #{id}")
int updateUser(User user);
@Delete("delete from user where id = #{uid}")
int deleteUser(@Param("uid") int id);
#{} ${} 区别
#{} 安全 ,预编译之后嵌入
${} 直接拼接 不安全
各有用处
.2 核心配置文件中绑定接口!(只能用class属性
<!--绑定接口-->
<mappers>
<mapper class="com.kuang.dao.UserMapper"/>
</mappers>
3,Lombok 简化代码工具类
在实体类上加注解即可!
@Data:无参构造,get、set、tostring、hashcode,equals
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
@ToString
@Getter
自动生成一些常用方法 非常建议使用
4,表关联时的复杂sql
.1多对一处理
<!--
思路:
1. 查询所有的学生信息
2. 根据查询出来的学生的tid,寻找对应的老师! 子查询
-->
复杂的结果用 resultMap
1.1按照查询嵌套处理
<select id="getStudent" resultMap="StudentTeacher">
select * from student
</select>
<resultMap id="StudentTeacher" type="Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<!--复杂的属性,我们需要单独处理 对象: association 集合: collection -->
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
association属性
property="teacher" type="Student"中的teacher 属性
column="tid" 外键
javaType="Teacher" type="Student"中的teacher 属性的类型
select="getTeacher" 对应mapper中的 sql语句
</resultMap>
<select id="getTeacher" resultType="Teacher">
select * from teacher where id = #{id}
</select>
1.2按照结果嵌套处理
<!--按照结果嵌套处理-->
<select id="getStudent2" resultMap="StudentTeacher2">
select s.id sid,s.name sname,t.name tname
from student s,teacher t
where s.tid = t.id;
</select>
<resultMap id="StudentTeacher2" type="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="Teacher">
<result property="name" column="tname"/>
</association>
</resultMap>
.2 一对多处理
1.按照结果嵌套处理
<!--按结果嵌套查询-->
<select id="getTeacher" resultMap="TeacherStudent">
select s.id sid, s.name sname, t.name tname,t.id tid
from student s,teacher t
where s.tid = t.id and t.id = #{tid}
</select>
<resultMap id="TeacherStudent" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<!--复杂的属性,我们需要单独处理 对象: association 集合: collection
javaType="" 指定属性的类型!
集合中的泛型信息,我们使用ofType获取
-->
<collection property="students" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
2,按照查询嵌套处理
<select id="getTeacher2" resultMap="TeacherStudent2">
select * from mybatis.teacher where id = #{tid}
</select>
<resultMap id="TeacherStudent2" type="Teacher">
<collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTeacherId" column="id"/>
</resultMap>
<select id="getStudentByTeacherId" resultType="Student">
select * from mybatis.student where tid = #{tid}
</select>
3,小结
- 关联 - association 【多对一】
- 集合 - collection 【一对多】
- javaType & ofType
- JavaType 用来指定实体类中属性的类型
- ofType 用来指定映射到List或者集合中的 pojo类型,泛型中的约束类型
5,动态sql
什么是动态SQL:动态SQL就是指根据不同的条件生成不同的SQL语句
动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多元素需要花时间了解。MyBatis 3 大大精简了元素种类,现在只需学习原来一半的元素便可。MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。
if
choose (when, otherwise)
trim (where, set)
foreach
<select id="queryBlogIF" parameterType="map" resultType="blog">
select * from mybatis.blog where 1=1
<if test="title != null">
and title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</select>
<select id="queryBlogChoose" parameterType="map" resultType="blog">
select * from mybatis.blog
<where>
<choose>
<when test="title != null">
title = #{title}
</when>
<when test="author != null">
and author = #{author}
</when>
<otherwise>
and views = #{views}
</otherwise>
</choose>
</where>
</select>
select * from mybatis.blog
<where>
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</where>
<update id="updateBlog" parameterType="map">
update mybatis.blog
<set>
<if test="title != null">
title = #{title},
</if>
<if test="author != null">
author = #{author}
</if>
</set>
where id = #{id}
</update>
select * from user where 1=1 and
<foreach item="id" collection="ids"
open="(" separator="or" close=")">
#{id}
</foreach>
(id=1 or id=2 or id=3)
SQL片段
有的时候,我们可能会将一些功能的部分抽取出来,方便复用!include标签引入 refid
<sql id="if-title-author">
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</sql>
<select id="queryBlogIF" parameterType="map" resultType="blog">
select * from mybatis.blog
<where>
<include refid="if-title-author"></include>
</where>
</select>
6,缓存 MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存
13.3、一级缓存
-
一级缓存也叫本地缓存: SqlSession
- 与数据库同一次会话期间查询到的数据会放在本地缓存中。
- 以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库;
-
二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
-
基于namespace级别的缓存,一个名称空间,对应一个二级缓存;
-
工作机制
- 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
- 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;
- 新的会话查询信息,就可以从二级缓存中获取内容;
- 不同的mapper查出的数据会放在自己对应的缓存(map)中;
步骤:
-
开启全局缓存
<!--显示的开启全局缓存--> <setting name="cacheEnabled" value="true"/>
-
在要使用二级缓存的Mapper中开启
<!--在当前Mapper.xml中使用二级缓存--> <cache/>
也可以自定义参数
<!--在当前Mapper.xml中使用二级缓存--> <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
-
测试
-
问题:我们需要将实体类序列化!否则就会报错!
Caused by: java.io.NotSerializableException: com.kuang.pojo.User
-
小结:
- 只要开启了二级缓存,在同一个Mapper下就有效
- 所有的数据都会先放在一级缓存中;
- 只有当会话提交,或者关闭的时候,才会提交到二级缓冲中!