数据持久化
持久化就是将程序的数据在持久状态和瞬时状态转化过程。
内存:断电即失
数据库:io文件持久化
生活:冷藏
为什么需要持久化?
有一些对象不能让他丢掉,内存太贵了。
持久层
Dao层 service 层 controller层
完成持久化工作的代码块
层界限十分明显
方便
传统的JDBC代码太复杂,简化,框架,自动化。
帮助程序员将数据存入数据库中。
更容易上手。技术没有高低之分。
优点:
优点:
最重要的一点:使用的人多。
思路:搭建环境 --> 导入MyBatis --> 编写代码 --> 测试
新建项目:
1 新建一个普通meaven项目
2 删除src目录
3 导入meaven依赖
导入相关meaven依赖
junit
junit
4.11
test
mysql
mysql-connector-java
8.0.21
org.mybatis
mybatis
3.5.2
2.2 创建一个模块
编写核心配置文件
编写mybatis工具类
package com.kuang.utils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
//第一步:获取sqlSessionFactory对象
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(resource);
} catch (IOException e) {
e.printStackTrace();
}
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
2.3 编写代码
实体类
package com.kuang.pojo;
public class User {
private int id;
private String name;
private String pwd;
public User(int id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}
public User() {
}
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 + '\'' +
'}';
}
}
Dao接口
接口实现类
测试代码
package com.kuang.dao;
import com.kuang.pojo.User;
import com.kuang.util.MybatisUtil;
import org.apache.ibatis.session.SqlSession;
import java.util.List;
public class TestMapper {
public static void main(String[] args) {
SqlSession sqlSession= MybatisUtil.getSqlSession();
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
List userList=userMapper.getUserList();
for(User user:userList){
System.out.println(user);
}
sqlSession.close();
}
}
namespace中的包名要和Dao/Mapper接口的包名一致
选择,查询语句;
id:就是对应的namespace中的方法名;
resultType : Sql语句执行的返回值;
parameterType : 参数类型;
sqlSession.commit();
假设,我们的实体类,或者数据库中的表,字段或者参数过多,我们应该考虑使用Map
//用万能Map插入用户
public void addUser2(Map map);
别名是mybatis中的名字。
xml文件
insert into user (id,name,password) values (#{userid},#{username},#{userpassword})
Map传递参数,直接在sql中取出key即可! 【parameter=“map”】
对象传递参数,直接在sql中取出对象的属性即可! 【parameter=“Object”】
只有一个基本类型参数的情况下,可以直接在sql中取到
多个参数用Map , 或者注解!
UserMapper.xml
insert into user(id,name,pwd) values(#{id},#{name},#{pwd})
insert into user(id,name,pwd) values(#{Id},#{Name},#{Pwd})
delete from user where id=#{id}
update user set name=#{name},pwd=#{pwd} where id=#{id}
Usermapper的接口
package com.kuang.mapper;
import com.kuang.pojo.User;
import java.util.List;
import java.util.Map;
public interface UserMapper {
public List getUserList();
public int addUser(User user);
public int addUser02(Mapmap);
public int deleteUserById(int id);
public int updateUser(User user);
public User getUserById(int id);
}
测试代码
package com.kuang.dao;
import com.kuang.mapper.UserMapper;
import com.kuang.pojo.User;
import com.kuang.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.Test;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class UserDaoTest {
@Test
public void test(){
SqlSession sqlSession= MybatisUtils.getSqlSession();
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
List userList=userMapper.getUserList();
for(User user:userList){
System.out.println(user);
}
sqlSession.commit();
sqlSession.close();
}
@Test
public void testadd(){
SqlSession sqlSession=MybatisUtils.getSqlSession();
UserMapper mapper=sqlSession.getMapper(UserMapper.class);
int flag=mapper.addUser(new User(4,"王五","123456"));
if(flag>0){
System.out.println("插入成功");
}else {
System.out.println("插入失败");
}
sqlSession.commit();
sqlSession.close();
}
@Test
public void testadd02(){
SqlSession sqlSession=MybatisUtils.getSqlSession();
UserMapper mapper=sqlSession.getMapper(UserMapper.class);
Map map=new HashMap();
map.put("Id",5);
map.put("Name","hahaha");
map.put("Pwd","1111111");
int flag=mapper.addUser02(map);
if(flag>0){
System.out.println("插入成功");
}else {
System.out.println("插入失败");
}
sqlSession.commit();
sqlSession.close();
}
@Test
public void testDetele(){
SqlSession sqlSession=MybatisUtils.getSqlSession();
UserMapper mapper=sqlSession.getMapper(UserMapper.class);
int flag=mapper.deleteUserById(5);
if(flag>0){
System.out.println("删除成功");
}else {
System.out.println("删除失败");
}
sqlSession.commit();
sqlSession.close();
}
@Test
public void testUpdate(){
SqlSession sqlSession=MybatisUtils.getSqlSession();
UserMapper mapper=sqlSession.getMapper(UserMapper.class);
int flag=mapper.updateUser(new User(1,"HAHAHA","111111"));
if(flag>0){
System.out.println("更新成功");
}else {
System.out.println("更新失败");
}
sqlSession.commit();
sqlSession.close();
}
@Test
public void testGetUser(){
SqlSession sqlSession=MybatisUtils.getSqlSession();
UserMapper mapper=sqlSession.getMapper(UserMapper.class);
User user=mapper.getUserById(1);
System.out.println(user);
sqlSession.close();
}
}
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
MyBatis 可以配置成适应多种环境
不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境
学会使用配置多套运行环境!
MyBatis默认的事务管理器就是JDBC ,连接池:POOLED
事务管理器(transactionManager)
在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]"):
数据源(dataSource)
不止一个类型
POOLED– 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这种处理方式很流行,能使并发 Web 应用快速响应请求。
我们可以通过properties属性来实现引用配置文件
这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。【db.poperties】
如果两个文件都有相同属性,优先使用外部配置文件
注意properties和typeAliases标签的顺序
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置.
意在降低冗余的全限定类名书写。
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:
一个配置完整的 settings 元素的示例如下:
// select * from user where id = #{id}
// 类型处理器
// select id,name,pwd from user where id = #{id}
id name pwd
id name password
resultMap
元素是 MyBatis 中最重要最强大的元素。ResultMap
的优秀之处——你完全可以不用显式地配置它们。
实质是一个JDBC Connection
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file
#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/jianghe.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sq1.PreparedStatement=DEBUG
Logger logger = Logger.getLogger(UserDaoTest.class);
logger.info("info: 测试log4j");
logger.debug("debug: 测试log4j");
logger.error("error:测试log4j");
将信息输出到日志文件中
SELECT * from user limit startIndex,pageSize
//分页
List getUserByLimit(Map map);
@Test
public void getUserByLimit(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
HashMap map = new HashMap();
map.put("startIndex",1);
map.put("pageSize",2);
List list = mapper.getUserByLimit(map);
for (User user : list) {
System.out.println(user);
}
}
@Select("select * from user")
List getUsers();
//方法存在多个参数,所有的参数前面必须加上@Param("id")注解
@Delete("delete from user where id = ${uid}")
int deleteUser(@Param("uid") int id);
${param}传递的参数会被当成sql语句中的一部分,比如传递表名,字段名
例子:(传入值为id)
order by ${param}
则解析成的sql为:
order by id
#{parm}传入的数据都当成一个字符串,会对自动传入的数据加一个双引号
例子:(传入值为id)
select * from table where name = #{param}
则解析成的sql为:
select * from table where name = "id"
为了安全,能用#的地方就用#方式传参,这样可以有效的防止sql注入攻击
package com.kuang.mapper;
import com.kuang.pojo.User;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List;
import java.util.Map;
public interface UserMapper {
@Select("select * from user")
public List getUserList();
@Insert("insert into user(id,name,pwd) values(#{id},#{name},#{pwd})")
public int addUser(User user);
@Insert("insert into user(id,name,pwd) values(#{Id},#{Name},#{Pwd})")
public int addUser02(Mapmap);
@Delete("delete from user where id=#{id}")
public int deleteUserById(int id);
@Update("update user set name=#{name},pwd=#{pwd} where id=#{id}")
public int updateUser(User user);
@Select("select * from user where id=#{id}")
public User getUserById(int id);
}
@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows
@val
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private String password;
}
多个学生一个老师;
package com.kuang.mapper;
import com.kuang.pojo.Student;
public interface StudentMapper {
public Student getStudent(int id);
}
package com.kuang;
import com.kuang.mapper.StudentMapper;
import com.kuang.mapper.TeacherMapper;
import com.kuang.pojo.Student;
import com.kuang.pojo.Teacher;
import com.kuang.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import java.util.List;
public class MyTest {
public static void main(String[] args) {
SqlSession sqlSession= MybatisUtils.getSqlSession();
StudentMapper mapper=sqlSession.getMapper(StudentMapper.class);
Student student=mapper.getStudent(1);
System.out.println(student);
}
}
一个老师多个学生;
对于老师而言,就是一对多的关系;
动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。
SELECT * FROM BLOG
WHERE
SELECT * FROM BLOG
WHERE
AND title like ‘someTitle’
update Author
username=#{username},
password=#{password},
email=#{email},
bio=#{bio}
where id=#{id}
title = #{title}
and author = #{author}
查询 : 连接数据库,耗资源
一次查询的结果,给他暂存一个可以直接取到的地方 --> 内存:缓存
我们再次查询的相同数据的时候,直接走缓存,不走数据库了
@Test
public void test2(){
SqlSession sqlSession=MybatisUtil.getSqlSession();
BlogMapper mapper=sqlSession.getMapper(BlogMapper.class);
Blog blog1=mapper.queryBlogById("2587f90269714b6aa78aaeb2a8a1b492");
Blog blog2=mapper.queryBlogById("2587f90269714b6aa78aaeb2a8a1b492");
System.out.println(blog1);
System.out.println(blog2);
System.out.println(blog1==blog2);
}
sqlSession.clearCache();
@Test
public void test3(){
SqlSession sqlSession=MybatisUtil.getSqlSession();
BlogMapper mapper=sqlSession.getMapper(BlogMapper.class);
Blog blog=mapper.queryBlogById("2587f90269714b6aa78aaeb2a8a1b492");
System.out.println(blog);
sqlSession.close();
SqlSession sqlSession1=MybatisUtil.getSqlSession();
BlogMapper mapper1=sqlSession1.getMapper(BlogMapper.class);
Blog blog1=mapper1.queryBlogById("2587f90269714b6aa78aaeb2a8a1b492");
System.out.println(blog1);
sqlSession1.close();
}
org.mybatis.caches
mybatis-ehcache
1.2.1
List userList = mapper.getUserLike("%李%");
select * from user where name like "%"#{value}"%"