目录
2.2、STDOUT_LOGGING标准日志输出,在设置中设置
1、解决属性名和字段名不一致的问题
解决方法:
1、起别名
select * from mybatis.user
select id,name,pwd as passwd from mybatis.user
2、resultMap
结果集映射
id name pwd
id name passwd
<!--结果集映射-->
<resultMap id="UserMap" type="User">
<!--column 对应数据库里的字段,property 对应实体类里的属性-->
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="pwd" property="pword"/>
</resultMap>
<select id="getUserList" resultMap="UserMap">
select * from mybatis.user
</select>
resultMap 元素是 MyBatis 中最重要最强大的元素。
ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。
2、日志
2.1、日志工厂
如果一个数据库操作出现了异常,我们需要排错,日志就是最好的帮手
SLF4J
LOG4J (掌握)
LOG4J2
JDK_LOGGING
COMMONS_LOGGING
STDOUT_LOGGING(掌握)
NO_LOGGING
2.2、STDOUT_LOGGING标准日志输出,在设置中设置
<!--设置日志-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
2.3、Log4J
用前得导包
啥是LOG4J?
- Log4j是 Apache 的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是 控制台 、文件、 GUI 组件,甚至是套接口服务器、 NT 的事件记录器、 UNIX Syslog 守护进程 等
- 我们也可以控制每一条日志的输出格式;
- 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。
1、先导log4j的包
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2、
#将等级为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/zhang.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.sql.PreparedStatement=DEBUG
简单的使用
1、在要使用log4j的类中,导入包import org.apache.log4j.Logger;
2、日志对象,参数为当前类的class
static Logger logger = Logger.getLogger(UserDaoTest.class);
@Test
public void log4jTest(){
logger.info("info:进入log4j");
logger.debug("info:进入log4j");
logger.error("info:进入log4j");
}
输出的log文件内容:
[INFO][22-10-08][com.zhang.dao.UserDaoTest]info:进入log4j
[DEBUG][22-10-08][com.zhang.dao.UserDaoTest]info:进入log4j
[ERROR][22-10-08][com.zhang.dao.UserDaoTest]info:进入log4j
3、分页
为什么分页?
减少数据的处理量
3.1、使用limit分页(物理分页)
select * from user limit startIndex,pageSize;
select * from user limit 3;[0,n-1]
select * from user limit 0,2;每一页显示两个从第0个人开始
使用Mybatis实现分页,核心SQL
接口:
List<User> getUserByLimit(Map<String,Integer> map);
Mapper.xml:
<select id="getUserByLimit" resultMap="UserMap" parameterType="map">
select * from mybatis.user limit #{startIndex},#{pageSize}
</select>
测试:
@Test
public void Timit(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
HashMap<String, Integer> map = new HashMap<>();
map.put("startIndex",0);
map.put("pageSize",2);
List<User> userByLimit = mapper.getUserByLimit(map);
for (User user : userByLimit) {
System.out.println(user);
}
sqlSession.close();
}
3.2、RowBounds分页
不使用SQL分页
1、接口
//分页二
List<User> getUserByRowBounds();
2、mapper.xml
<!--分页2-->
<select id="getUserByRowBounds" resultMap="UserMap">
select *from mybatis.user
</select>
3、测试
@Test
public void getUserByRowBounds(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//通过RowBounds实现分页
RowBounds rowBounds = new RowBounds(1, 2);
//通过Java代码层面进行分页(不太建议)
List<User> User = sqlSession.selectList("com.zhang.dao.UserMapper.getUserByRowBounds",null,rowBounds);
for (com.zhang.pojo.User user : User) {
System.out.println(user);
}
sqlSession.close();
}
3.3、Mybatis分页插件 PageHelper
官方网址:https://pagehelper.github.io/
4、使用注解开发
关于接口的理解。
接口从更深层次的理解,应是定义(规范,约束)与实现(名实分离的原则)的分离。
接口的本身反映了系统设计人员对系统的抽象理解。
接口应有两类:第一类是对一个个体的抽象,它可对应为一个抽象体(abstract class);
第二类是对一个个体某一方面的抽象,即形成一个抽象面(interface);
一个体有可能有多个抽象面。
4.1、注解在接口上的实现
@Select("select id,name,pwd as passwd from mybatis.user")
List<User> getUsers();
//方法存在多个参数时需要使用@Param注解,引用对象不需要用@Param,像User之类的
@Select("select id,name,pwd as passwd from mybatis.user where id = #{id}")
User getUserById(@Param("id") int id);
@Insert("insert into user(id, name, pwd) VALUES (#{id},#{name},#{passwd})")
int add(User user);
@Update("update user set name = #{name}, pwd = #{passwd} where id = #{id}")
int updateUser(User user);
@Delete("delete from user where id = #{uid}")
int deleteUser(@Param("uid") int id);
4.2、在核心配置文件中绑定接口
<mappers>
<mapper class="com.zhang.dao.UserMapper"/>
</mappers>
4.3、测试
@Test
public void Test(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> users = mapper.getUsers();
for (User user : users) {
System.out.println(user);
}
sqlSession.close();
}
@Test
public void add(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int user = mapper.add(new User(7,"iiii","9999444"));
System.out.println(user);
sqlSession.close();
}
本质:反射机制的实现
底层是动态代理
5、Mybatis获取参数的两种方式
#{}和${}
5.1、单个字面量类型的参数
若mapper接口中的方法参数为单个的字面量类型
可以使用${}和#{}以任意的名称获取参数的值,${}需要手动加单引号
5.2、多个字面量类型的参数
如果mapper接口中的方法参数为多个时
此时Mybatis会自动将这些参数放在一个map集合中,以arg1、arg2..为键,以参数为值;以param1,param2...为键,以参数为值;因此只需要通过${}和#{}访问map集合的键就可以获取相对应的值,${}需要手动加单引号
关于@Param()注解
- 基本类型的参数或者String类型的,需要加上
- 引用类型不用加 像User实体类这样的
- 如果只有一个基本类型的话可以忽略,但还是建议加上
- 我们在SQL引用的就是这里的@Param()中设定的属性名
6、Mybatis详细执行流程
7、Lombok
Lombok是一个Java库,能自动插入编辑器并构建工具,简化Java开发。通过添加注解的方式,不需要为类编写getter或eques方法,同时可以自动化日志变量。
简而言之:Lombok能以简单的注解形式来简化java代码,提高开发人员的开发效率。
怎么用?
1、在idea里安装Lombok插件
2、导入projectlombok的jar包
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</dependency>
3、有哪些注解?
@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, 有参@RequiredArgsConstructor and @NoArgsConstructor 无参
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data get,set,toString,hasCode,equals ,无参构造
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows
8、多对一
8.1、啥意思?
- 多个学生对应一个老师
- 对于学生而言,是关联 多个学生关联一个老师
- 对老师而言,是集合,一个老师对应多个学生
CREATE TABLE `teacher` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO teacher(`id`, `name`) VALUES (1, '张老师');
CREATE TABLE `student` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
`tid` INT(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fktid` (`tid`),
CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小红', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小张', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');
8.2、测试环境搭建
- 导入lombok,自己手写实体类方法也行
- 新建实体类Teacher、Student
- 创建Mapper接口
- 创建mapper.xml文件
- 在核心配置文件中绑定mapper接口或文件
- 测试能否成功
8.3、按照查询嵌套处理(类似于子查询)
<!--
1、查询所有学生信息
2、根据查询出来的学生的tid,寻找对应的老师
-->
<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 对象用-->
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
<!--collection 集合用-->
<!-- <collection property=""/>-->
</resultMap>
<select id="getTeacher" resultType="Teacher">
select *from teacher
</select>
8.4、按照结果嵌套处理(更快)
<!--方法二:根据结果嵌套处理 (更快)-->
<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>
9、一对多处理
搭建完环境后对实体类做些修改
public class Teacher {
private int id;
private String name;
//一个老师对应多个学生
private List<Student> students;
}
public class Student {
private int id;
private String name;
//一个学生对应一个老师
private int tid;
}
9.1、按照查询嵌套处理(子查询)
<!--方式二:根据查询嵌套(子查询)-->
<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="getStudentByTeacher" column="id"/>
</resultMap>
<select id="getStudentByTeacher" resultType="Student">
select *from mybatis.student where tid = #{tid}
</select>
9.2、按照结果嵌套处理(更快推荐)
<!--方式一:根据结果嵌套查询-->
<select id="getTeacherStudent" resultMap="TeacherStudent">
select s.id sid,s.name sname,t.name tname,t.id tid
from mybatis.student s,mybatis.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"/>
<!--javaType指定属性类型
像集合中的泛型信息,需要使用ofType获取
-->
<collection property="students" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
小结:
- 关联 association 多对一
- 集合 collection 一对多
- javaType 和 ofType
javaType 用来指定实体类中属性的类型
ofType用来指定映射到List或者集合中的pojo类型,泛型中的约束类型
注意:
- 保证SQL的可读性,尽量通俗易懂
- 注意一对多和多对一中,属性和字段的问题
- 如果问题不好排错,可以使用日志,建议使用Log4j
需要研究的:Mysql引擎、InnoDB底层原理、索引、索引优化