前置环境:
- JDK18
- 8.0.27
- maven 3.8.5
- IDEA
1,简介
1.1,什么是MyBatis
- MyBatis 是一款优秀的持久层框架
- 它支持自定义 SQL、存储过程以及高级映射。
- MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
- MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
- MyBatis本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation迁移到了google code,并且改名为MyBatis。
- 2013年11月迁移到Github。
如何获得MyBatis?
- maven仓库
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.9</version> </dependency>
- GitHub : GitHub - mybatis/mybatis-3: MyBatis SQL mapper framework for Java
- MyBatis中文文档:MyBatis中文网
1.2,持久化
数据持久化
- 持久化就是将程序的数据在持久状态和瞬时状态转换的过程
- 内存:断电即失
- 生活:冷藏,罐头
为什么需要持久化?
- 有一些对象不能让他丢失
- 内存太贵了
1.3,持久层
Dao层,Service层,Controller层...
- 完成持久化的代码块
- 层是界限十分明显的
1.4,为什么学MyBatis
- 帮助程序员将数据存储到数据库中
- 方便
- 传统的JDBC代码太复杂了
- 不用MyBatis也可以,用了只是更容易上手。技术没有高低之分
- 优点:
- 简单易学
- 灵活
- sql和代码的分离,提高了可维护性。
-
提供映射标签,支持对象与数据库的orm字段关系映射。
-
提供对象关系映射标签,支持对象关系组建维护。
-
提供xml标签,支持编写动态sql。
最重要的一点:使用的人多!
2.第一个MyBatis程序
思路:搭建环境-->导入MyBaits-->编写代码-->测试
2.1,搭建环境
数据库环境搭建:
-- 创建数据库
create database if not exists `mybatis`;
-- 进入数据库
use `mybatis`;
-- 创建表
create table `user`(
`id` int not null,
`name` varchar(10) default null,
`pwd` varchar(40) default null,
primary key (`id`)
)engine=innodb default charset=utf8;
-- 向数据库插入数据
insert into `user`(`id`,`name`,`pwd`) values (1,'小步','123456789');
新建项目:
- 创建一个maven项目
- 删除src目录
- 导入Maven依赖
<!-- 项目依赖 -->
<dependencies>
<!-- MySql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<!-- MyBatis依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<!-- junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
2.2,创建一个模块
- 编写MyBatis配置文件
<?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表示核心配置文件--> <configuration> <!-- 环境配置:可以配置多套环境,可选择默认的环境 --> <environments default="development"> <!-- 设置一套环境 --> <environment id="development"> <!-- 事务管理默认的是JDBC --> <transactionManager type="JDBC"/> <!-- 配置数据库 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf8&serverTimezone=Asia/Shanghai"/> <property name="username" value="root"/> <property name="password" value="98526"/> </dataSource> </environment> </environments> </configuration>
- 编写MyBatis工具类
package com.xiao.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; //SqlSessionFactory--> SqlSession public class MyBatisUtils { private static SqlSessionFactory sqlSessionFactory; static{ try { //使用MyBatis获取SqlSessionFactory对象 String resources="mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resources); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } /** * 既然有了SqlSessionFactory就可以获取SqlSession的实例了 * SqlSession包含了面向数据执行sql的所以方法 * @return 返回SqlSession的实例 */ public static SqlSession getSqlSession(){ return sqlSessionFactory.openSession(); } }
- 编写实体类
package com.xiao.pojo; import lombok.Data; @Data public class User { private Integer id; private String name; private String pwd; }
- Dao层接口
public interface UserDao { List<User> getUserList(); }
- 接口实现类由原来的UserDaoImpl转换为Mapper配置文件
<?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会绑定一个对应的Mapper/Dao接口--> <mapper namespace="com.xiao.dao.UserDao"> <!-- id="对应接口的方法名 resultType="返回的类型"--> <select id="getUserList" resultType="com.xiao.pojo.User"> select * from `user`; </select> </mapper>
2.3,测试
注意点一:如果遇到Type interface com.xiao.dao.UserDao is not known to the MapperRegistry.请注意:每一个Mapper.xml都需要在MyBatis核心配置文件中注册!
-
junit测试
<!-- 每一个Mapper.xml都需要在MyBatis核心配置文件中注册! -->
<mappers>
<mapper resource="com/xiao/dao/UserMapper.xml"/>
</mappers>
注意点二:由于Maven是约定大于配置,所以我们可能会遇到写的配置文件无法生效或导出的问题,则可以在Maven的pom.xml中加入:
<!-- 在build配置resources,来防止资源导出失败的问题! -->
<build>
<resources>
<!-- 配置文件过滤 -->
<resource>
<!-- 配置路径 -->
<directory>src/main/java</directory>
<!-- 配置过滤文件 -->
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
<!-- 确认过滤 -->
<filtering>true</filtering>
</resource>
<!-- 同理 -->
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
注意点三:如果出现了Cause: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 4; columnNumber: 14; 1 字节的 UTF-8 序列的字节 1 无效。
则需要把xml文件开头的UTF-8设置为UTF8!
3,CRUD
3.1,namespace
namespace的包名要和Dao/Mapper接口的包名一致
3.2,select
选择,查询语句
- id:对应Mapper的方法名
- resultType:sql语句的返回值!
- parameterType:参数类型!
- 编写接口
//根据id查询用户 User getUserById(Integer id);
- 编写Mapper
<select id="getUserById" resultType="com.xiao.pojo.User" parameterType="Integer"> select * from `user` where id = #{id}; </select>
- 测试
@Test//查询用户 public void Test(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); UserDao mapper = sqlSession.getMapper(UserDao.class); System.out.println(mapper.getUserById(1)); }
3.3.Insert
同:
//增加用户
Integer addUser(User user);
<!-- 对象中的属性可以之间取出来 -->
<insert id="addUser" parameterType="com.xiao.pojo.User">
insert into `user`
values (#{id}, #{name}, #{pwd});
</insert>
@Test//测试插入
public void Test01(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
System.out.println(mapper.addUser(new User(4,"小九","132456")));
//修改数据必须要提交事务
sqlSession.commit();
sqlSession.close();
}
3.4,update
同:
//修改用户
void updateUser(User user);
<update id="updateUser" parameterType="com.xiao.pojo.User">
update `user` set name=#{name},pwd=#{pwd} where id=#{id};
</update>
@Test//测试修改数据
public void Test02(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
mapper.updateUser(new User(4, "小九","123465798"));
sqlSession.commit();
}
3.5,delete
同:
//删除用户
Integer deleteUser(Integer id);
<delete id="deleteUser" parameterType="Integer">
delete from `user` where id=#{id};
</delete>
@Test//删除用户
public void Test03(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
System.out.println(mapper.deleteUser(4));
sqlSession.commit();
}
注意:修改数据需要提交事务!
3.6,分析错误
- 标签不能匹配错
- resource绑定Mapper需要使用路径
- 程序配置文件必须符合规范
- Maven资源没有导出问题!
3.7,万能Map
假设,我们的实体类,或者数据库中的表,字段或者参数过多我们应该考虑使用Map
//万能的Map
Integer addMapUser(Map<String,Object> map);
<insert id="addMapUser" parameterType="Map">
insert into `user`values (#{id}, #{name}, #{pwd});
</insert>
@Test //测试万能的Map
public void Test04(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
Map<String, Object> map = new HashMap<>();
map.put("id",4);
map.put("name","小八");
map.put("pwd","15826714480");
System.out.println(mapper.addMapUser(map));
sqlSession.commit();
}
- Map传递的参数可以直接在sql取出key即可![parameterType="Map"]
- 对象传递参数可直接在对象中取出属性即可![parameterType="com.xiao.pojo.User"]
- 只有一个基本类型可以直接在sql中取到! [parameterType="Integer"]
- 多个参数使用Map或者注解!
3.8,思考题
模糊查询怎么写?
- java执行代码时传递通配符%%
- 在sql语句中拼接
4,配置解析
4.1,核心配置文件
- mybatis-config.xml
- MyBatis的配置文件包含了会深深影响影响MyBatis行为和设置的属性信息
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
4.2,环境配置(environments)
MyBatsi可以配置适应多种环境
不过需要记住:尽管可以配置多个环境,但每个SqlSessionFactory实例只能选择一种环境!
- MyBatis的默认事务管理器为:JDBC
- MyBatis的连接池默认:POOLED
4.3, 属性(properties)
我们可以通过properties属性来实现引用配置文件 。
这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。【db.properties】
编写一个数据库配置文件【db.properties】:
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf8&serverTimezone=Asia/Shanghai
user=root
password=98526
在核心配置文件中引入:
<!-- 引入properties配置文件 -->
<properties resource="db.properties">
<!-- 同时也可以添加配置文件的内容 -->
<property name="pwd" value="98526"/>
</properties>
- 可以直接引入外部文件
- 可以在其中增加属性配置
- 如果两个文件有同一个字段,优先使用外部配置文件!
4.4,类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字,是为了降低冗余的代码。
<!-- 给类起别名 -->
<typeAliases>
<typeAlias type="com.xiao.pojo.User" alias="User"/>
</typeAliases>
也可以指定一个包名,MyBatis会在指定包名下搜索所需要的java Bean 比如:
扫描类的包,他的默认别名就为这个类的类名(建议勇小写的):
<!-- 给类起别名 -->
<typeAliases>
<package name="com.xiao.pojo"/>
</typeAliases>
- 在实体类比较小的时候使用第一种方式,反之则使用第二种方式!
- 第一种可以自定义别名,第二种则不行,但是也可以通过注解进行别名如:
4.5,设置(settings)
这是 MyBatis 中极为重要的调整设置,他们会改名MyBatis的运行时行为!
4.6,其他配置
- typeHandlers(类型处理器)
- objectFactory(对象工厂)
- plugins(插件)
- mybatis-generator-core
- mybatis-plus
- 通用Mapper
4.7,映射器(mappers)
在核心文件种注册我们绑定的Mapper文件
方式一:【推荐使用】
<!-- 每一个Mapper.xml都需要在MyBatis核心配置文件中注册! -->
<mappers>
<mapper resource="com/xiao/dao/UserMapper.xml"/>
</mappers>
方式二:使用class文件绑定注册
<!-- 每一个Mapper.xml都需要在MyBatis核心配置文件中注册! -->
<mappers>
<mapper class="com.xiao.dao.UserMapper"/>
</mappers>
注意点:
- 接口和它的Mapper配置文件必须同名!
- 接口和它的Mapper必须在同一个包下!
方式三:使用扫描包进行注入绑定与方式二注意点相同(只是范围更大)
<!-- 每一个Mapper.xml都需要在MyBatis核心配置文件中注册! -->
<mappers>
<package name="com.xiao.dao"/>
</mappers>
练习:
- 将数据库配置文件外部引入
- 给类pojo的类起个别名
- 把UserDao接口名改为UserMapper接口并且和UserMapper.xml文件放在同一个包下
4.8,生命周期和作用域
生命周期和作用域是至关重要的,因为错误的使用会导致非常严重的并发问题.
SqlSessionFactoryBuilder
- 一旦创建了SqlSessionFactoryBuilder就不需要它了
- 局部变量
SqlSessionFactory
- 说白了就是数据库连接池
- SqlSessionFactory一旦被创建就应该在应用运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例.
- 因此SqlSessionFactory的最佳作用域是应用作用域
- 最简单的就是单例模式或者静态单例模式
SqlSession
- 链接到链接池的一个请求
- SqlSession的实例是线程不安全的,因此是不能被共享的,所以他的最佳作用域是请求或方法作用域.
- 用完之后赶紧关闭,否则资源被占用.
这里面每一个Mapper代表着一个具体的业务!
5,解决属性名和字段名不一致的问题
数据库中的字段:
新建一个项目拷贝之前的,测试实体类字段不一致的情况
@Data
@AllArgsConstructor
@Alias("user")
public class User {
private Integer id;
private String name;
private String password;
}
测试出现问题:
select * from `user` where id = #{id};
//类型处理器
select id,name,password from `user` when id= #{id};
解决方案:
- 起别名
select id,name,pwd as password from `user` where id = #{id};
5.1,resultMap映射
结果集映射:
id name pwd
id name password
<!-- 结果集映射 -->
<resultMap id="UserMapper" type="com.xiao.pojo.User">
<!-- column数据库中的字段映射实体类的字段property -->
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="pwd" property="password"/>
</resultMap>
<select id="getUserById" parameterType="Integer" resultMap="UserMapper">
select * from `user`where id = #{id};
</select>
- resultMap是MyBatis中最重要最强大的元素
- resultMap的设计思想是,对于简单的语句根本不需要配置显示的结果集,而对于复杂的语句只需要描述他们的关系就可以了
- resultMap最优秀的地方在于虽然你已经对他足够了解了,但是更不就不需要显示的用到他们
- 如果世界总是这么简单就好了.
之后讲:
6,日志
6.1,日志工厂
如果一个数据库出现了异常我们需要排错,日志是最好的助手!
曾经:sout,debug
现在:日志工厂
- SLF4J
- LOG4J 【掌握】
- LOG4J2
- JDK_LOGGING
- COMMONS_LOGGING
- STDOUT_LOGGING 【掌握】
- NO_LOGGING
在MyBatis中具体使用哪一个日志实现,在设置中约定!
STDOUT_LOGGING 标准日志输出!
在MyBaits核心配置中配置日志!
<!-- 配置日志 -->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
6.2,LOG4J
什么使LOG4J:
- Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件
- 我们也可以控制每一条日志的输出格式
- 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。
- 可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
1.导入Log4j的包:
<!-- LoganJ -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2.log4j.properties配置文件
# 日志等级
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.RollingCalendar
log4j.appender.file.File=./log/xiao.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.PreparedStatement=DEBUG
3.配置log4j的日志实现
<!-- 配置日志 -->
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
4.Log4j的使用!直接测试运行
简单使用:
- 在使用Log4j的类中,导入包org.apache.log4j.Logger
- 日志对象参数为class:ogger logger = Logger.getLogger(TestUser.class)
- 日志级别:debug,info,warn,error
7.分页
思考:为什么要分页?
- 减少数据处理量
使用Limit分页
select * form 表名 limit startIndex,PageSize;
select * from user limit 3; -- [0,3]
使用MyBaits进行分页核心sql:
1.接口:
//分页
List<User> getUserByLimit(Map<String,Integer> map);
2.Mapper配置文件
<!-- 分页实现 -->
<select id="getUserByLimit" parameterType="map" resultType="com.xiao.pojo.User">
select * from `user` where `id` limit #{startIndex},#{sizePage};
</select>
3.测试
//测试分页
@Test
public void Test01(){
//1.获得SqlSession对象
try(SqlSession sqlSession = MyBatisUtils.getSqlSession();) {
//2.执行Sql
UserDao mapper = sqlSession.getMapper(UserDao.class);
HashMap<String, Integer> obj = new HashMap<>();
obj.put("startIndex",0);
obj.put("sizePage",3);
List<User> userByLimit = mapper.getUserByLimit(obj);
for (User user : userByLimit) {
System.out.println(user);
}
}
}
7.1, RowBounds分页
不在使用sql进行分页
1.接口:
//分页2
List<User> getUserByRowBounds();
2.Mapper配置文件
<!-- 分页实现2 -->
<select id="getUserByRowBounds" resultType="com.xiao.pojo.User">
select * from `user`;
</select>
3.测试:
//测试分页2
@Test
public void Test02(){
//1.获得SqlSession对象
try(SqlSession sqlSession = MyBatisUtils.getSqlSession();) {
//2.RowBounds实现
RowBounds rowBounds = new RowBounds(0,2);//同时startIndex,endPage
//3.执行Sql
List<User> obj = sqlSession.selectList("com.xiao.dao.UserDao.getUserByRowBounds", null, rowBounds);
System.out.println(obj);
}
}
7.2,分页插件
了解即可...
8,使用注解开发
8.1,面向接口编程
- 大家之前都学过面向对象编程,也学习过接口,但真实开发中我们会选择面向接口编程.
- 根本原因是为了:“解耦”,可拓展,提供复用,分层开发中上层不用管具体实现,大家都遵守共同标准,使得开发更加的容易,规范性更好。
- 在一个面向对象的系统中,系统各种功能都是由许许多多不同对象协作完成的。在这种情况下,各个对象内部是如何实现的对于系统设计人员就不那么重要了;
- 而各个对象之间的协作关系,则成为系统设计的关键。小到不同类之间的通信,大到各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要内容。面向接口编程是安装这种编程思想来编程.
关于接口的理解
- 接口更深层次的理解,应是定义(规范,约束)与实现(名实分离的原则)的分离.
- 接口本身反应了系统设计人员对系统的抽象理解
- 接口应该有两类:第一类是对一个个体的抽象,它可以对应为抽象体(abstract class),第二类是对一个个体某一方面的抽象,即形成一个抽象面(interface),一个个体可能有多个抽象面。抽象体是与抽象面有区别的。
三个面向区别
- 面向对象是指,我们考虑问题时以对象为单位,考虑它的属性及方法。
- 面向过程是指,我们考虑问题时以一个具体的流程(事务过程)为单位,考虑它的实现.
- 接口设计与非接口设计是针对复用技术而言的,与面向(过程)对象不是一个问题,更多的是体现对系统的整体架构.
8.2,使用注解开发
1.在接口上实现
//查询全部的用户
@Select("select * from user")
List<User> getUser();
2.需要在核心配置文件中绑定接口!
<!-- 绑定接口 -->
<mappers>
<mapper class="controller.UserMapper"/>
</mappers>
3.测试
@Test
public void test01(){
//底层主要应用反射
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> user = mapper.getUser();
System.out.println(user);
}
本质:反射机制实现
底层:动态代理
MyBatis详细执行流程!
8.3,CRUD
我们可以在获取SqlSession时设置自动提交设置:
/**
* 既然有了SqlSessionFactory就可以获取SqlSession的实例了
* SqlSession包含了面向数据执行sql的所以方法
* @return 返回SqlSession的实例
*/
public synchronized static SqlSession getSqlSession(){
return sqlSessionFactory.openSession(true);//设置为true自动提交
}
编写接口增加注释:
//通过id获取用户
@Select("select * from user where id=#{id}")
List<User> getUserByID(@Param("id") Integer id);
//增加
@Insert("insert into user values(#{id},#{name},#{pwd})")
void addUser(@Param("id") Integer id,@Param("name") String name,@Param("pwd") String pwd);
//修改
@Update("update user set id=#{id},name=#{name},pwd=#{pwd} where id=#{updateId}")
void updateUser(@Param("updateId") Integer updateId,@Param("id") Integer id,@Param("name") String name,@Param("pwd") String pwd);
//删除
@Delete("delete from user where id=#{id}")
void delete(@Param("id") Integer id);
测试类:注意[我们必须要将接口注册绑定到我们的核心配置文件中]
8.4,关于Param()注解
- 基本类型的参数或者String类型,需要加上
- 引用类型不需要加
- 如果一个基本类型可以忽略但是建议大家都加上!
- 我们在SQL中引用的就是我们这里的@Param("id")中设定的属性
${}与#{}的区别:
- #{}与JDBC一样创建prearedStatement参数占位符并安全设置参数(就像使用 ? 一样),安全迅速,转义字符
- ${} 采用的是字符串拼接参数的形式,不太安全,当传入参数为字段名,表名,排序方式,固定常量则可以使用。不转义字符串,有风险,同时存在sql注入,一般设置固定变量,例如字段名
9,Lombok
官方介绍:Project Lombok is a java library that automatically plugs into your editor and build tools, spicing up your java.Never write another getter or equals method again, with one annotation your class has a fully featured builder, Automate your logging variables, and much more.
翻译:ProjectLombok是一个java库,可以自动插入到编辑器和构建工具中,提高java的性能。永远不要再编写另一个getter或equals方法,使用一个注释,你的类就有了一个功能齐全的生成器,自动化了你的日志变量,等等。
使用步骤:
1.在IDE中安装lombok的插件
2.在项目中导入lombok的jar包
<!-- 实体类工具 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
@Data :get,set,toString,equals,hashCode
@AllArgsConstructor:全部构造方法
@Getter:get方法
@Setter: set方法
@ToString:toString方法
@EqualsAndHashCode:equals和HashCode方法
10,多对一处理
- 多个学生对应一个老师
- 对于学生这边而言:关联..多个学生关联一个老师![多对一]
- 对于老师而言,集合,一个老师,有很多学生[一对多]
sql:
-- 老师表
create table `teacher`(
`id` int not null,
`name` varchar(30) default null,
primary key(`id`)
)engine=innodb default charset=utf8;
-- 插入老师
insert into `teacher` values(1,"小布");
-- 学生表
create table `student`(
`id` int not null,
`name` varchar(30) default null,
`tid` int default null,
primary key (`id`),
key (`tid`)
);
-- 插入数据
insert into `student` values(1,'小七',1);
insert into `student` values(2,'小八',1);
insert into `student` values(3,'小步',1);
insert into `student` values(4,'小九',1);
测试环境搭建:
- 导入lombok
- 新建实体类Teacher,Student
- 建立Mapper接口
- 建立Mapper.xml文件
- 在核心配置文件中绑定注册
- 测试查询是否能够成功!
按查询嵌套处理
1、给StudentMapper接口增加方法
//获取所有学生及对应老师的信息
public List<Student> getStudents();
2、编写对应的Mapper文件
<?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.kuang.mapper.StudentMapper">
<!--
需求:获取所有学生及对应老师的信息
思路:
1. 获取所有学生的信息
2. 根据获取的学生信息的老师ID->获取该老师的信息
3. 思考问题,这样学生的结果集中应该包含老师,该如何处理呢,数据库中我们一般使用关联查询?
1. 做一个结果集映射:StudentTeacher
2. StudentTeacher结果集的类型为 Student
3. 学生中老师的属性为teacher,对应数据库中为tid。
多个 [1,...)学生关联一个老师=> 一对一,一对多
4. 查看官网找到:association – 一个复杂类型的关联;使用它来处理关联查询
-->
<select id="getStudents" resultMap="StudentTeacher">
select * from student
</select>
<resultMap id="StudentTeacher" type="Student">
<!--association关联属性 property属性名 javaType属性类型 column在多的一方的表中的列名-->
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>
<!--
这里传递过来的id,只有一个属性的时候,下面可以写任何值
association中column多参数配置:
column="{key=value,key=value}"
其实就是键值对的形式,key是传给下个sql的取值名称,value是片段一中sql查询的字段名。
-->
<select id="getTeacher" resultType="teacher">
select * from teacher where id = #{id}
</select>
</mapper>
3、编写完毕去Mybatis配置文件中,注册Mapper!
4、注意点说明:
<resultMap id="StudentTeacher" type="Student">
<!--association关联属性 property属性名 javaType属性类型 column在多的一方的表中的列名-->
<association property="teacher" column="{id=tid,name=tid}" javaType="Teacher" select="getTeacher"/>
</resultMap>
<!--
这里传递过来的id,只有一个属性的时候,下面可以写任何值
association中column多参数配置:
column="{key=value,key=value}"
其实就是键值对的形式,key是传给下个sql的取值名称,value是片段一中sql查询的字段名。
-->
<select id="getTeacher" resultType="teacher">
select * from teacher where id = #{id} and name = #{name}
</select>
5、测试
@Test
public void testGetStudents(){
SqlSession session = MybatisUtils.getSession();
StudentMapper mapper = session.getMapper(StudentMapper.class);
List<Student> students = mapper.getStudents();
for (Student student : students){
System.out.println(
"学生名:"+ student.getName()
+"\t老师:"+student.getTeacher().getName());
}
}