本篇文章为你整理了Mybatis完整版详解(mybatis简单介绍)的详细内容,包含有mybatis. mybatis简单介绍 mybatisutil mybatisorm Mybatis完整版详解,希望能帮助你了解 Mybatis完整版详解。
搭建一个数据库
新建一个maven项目,并导入maven依赖,要注意导入mybatis时需要手动开启Tomcat的bin目录下startup.sh(只针对本机,Windows开启startup.bat)
dependencies
dependency
groupId mysql /groupId
artifactId mysql-connector-java /artifactId
version 8.0.28 /version
/dependency
dependency
groupId org.mybatis /groupId
artifactId mybatis /artifactId
version 3.5.6 /version
/dependency
dependency
groupId junit /groupId
artifactId junit /artifactId
version 4.13.1 /version
/dependency
/dependencies
2.创建一个模块
编写mybatis的核心配置文件
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
environments default="development"
environment id="development"
transactionManager type="JDBC"/
dataSource type="POOLED"
!-- amp;在xml文件中与符号需要这样来转义--
property name="driver" value="com.mysql.jdbc.Driver"/
property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai amp;useSSL=true amp;useUnicode=true amp;characterEncoding=utf8"/
property name="username" value="root"/
property name="password" value="root123456"/
/dataSource
/environment
/environments
!-- 每一个mapper.xml都需要在Mybatis核心配置文件中注册--
mappers
mapper resource="com/tang/dao/UserMapper.xml"/
/mappers
/configuration
注意:这里如果没写加载驱动的话会报以下错误
org.apache.ibatis.exceptions.PersistenceException: Error querying database. Cause: java.lang.NullPointerException: Cannot invoke "Object.hashCode()" because "key" is null
但是写了又会说会自动加载,加载多余,不过这并不是错误,因此还是写上安全
编写mybatis工具类
//sqlSessionFactory-- sqlSession
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static{
try {
//使用Mybatis第一步,获取sqlSessionFactory对象
//这三行代码是从mybatis中文文档中获取到的,规定这么写的
String resource = "mybatis-config.xml";//这里写上自己的mybatis配置文件的文件名即可
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
//既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
// SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。
public static SqlSession getSqlSession(){
SqlSession sqlSession = sqlSessionFactory.openSession();
return sqlSession;
3.编写代码
字段名和数据里的字段一一对应
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 + \ +
};
Dao接口
public interface UserDao {
List User getUserList();
接口实现类由Impl转为一个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=绑定一个对应的Dao/Mapper接口,等价于以前去实现接口并重写方法--
mapper namespace="com.tang.dao.UserDao"
!-- select查询语句 --
!--id等价于以前去实现接口并重写方法 resultType:执行sql返回的结果集,仅需要返回接口的方法中的泛型类型即可 --
select id="getUserList" resultType="com.tang.pojo.User"
select * from mybatis.user
/select
/mapper
org.apache.ibatis.binding.BindingException: Type interface com.tang.dao.UserDao is not known to the MapperRegistry.
若在pom中没有以下代码则resources下的配置文件和java目录下的xml配置文件就不会被打包,也就是在target中并没有相应的class文件
build
resources
resource
directory src/main/resources /directory
includes
include **/*.properties /include
include **/*.xml /include
/includes
filtering true /filtering
/resource
resource
directory src/main/java /directory
includes
include **/*.properties /include
include **/*.xml /include
/includes
filtering true /filtering
/resource
/resources
/build
*测试代码:
public class UserDaoTest {
@Test
public void test(){
//第一步:获得sqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
//方式一:getMapper 执行SQL
UserDao userDao = sqlSession.getMapper(UserDao.class);
List User userList = userDao.getUserList();
for(User user: userList){
System.out.println(user);
//关闭SQLSession
sqlSession.close();
编写对应Dao中的sql语句
select id="getUserById" parameterType="int" resultType="com.tang.pojo.User"
select * from mybatis.user where id= #{id}
/select
//查询指定用户
@Test
public void getUserByID(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
User user = mapper.getUserById(1);
System.out.println(user);
sqlSession.close();
2.Insert
//添加一个用户
int addUser(User user);
编写对应Dao中的sql语句
insert id="addUser" parameterType="com.tang.pojo.User"
insert into mybatis.user(id,name,pwd) values(#{id},#{name},#{pwd})
/insert
//添加用户
@Test
public void addUserTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
mapper.addUser(new User(4,"twq","1233"));
sqlSession.commit();//增删改必须要提交事务,否则在数据库中就无法查看增删改后的结果
sqlSession.close();
3.update
//修改一个用户
int updateUser(User user);
编写对应Dao中的sql语句
update id="updateUser" parameterType="com.tang.pojo.User"
update mybatis.user set name=#{name},pwd=#{pwd} where id=#{id};
/update
//修改用户
@Test
public void updateUserTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
mapper.updateUser(new User(1,"唐","1234"));
sqlSession.commit();
sqlSession.close();
4.delete
//删除一个用户
int deleteUser(int id);
编写对应Dao中的sql语句
delete id="deleteUser" parameterType="int"
delete from mybatis.user where id=#{id};
/delete
@Test
public void deleteUserTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
mapper.deleteUser(2);
sqlSession.commit();
sqlSession.close();
运行前user中表的数据
运行增删改查之后结果图
5.万能的map
目的:将user表中id=1的name改为“唐三唐昊”
//万能的map
int updateUser2(Map String,Object map);
对应Dao中sql代码
update id="updateUser2" parameterType="map"
-- 这里就没有必要在把user中的所有字段都写进来,用到哪个就可以写哪个字段,且传进去的字段名可以任意写
update mybatis.user set name=#{username} where id=#{userid};
/update
测试代码
//map实现用户修改
@Test
public void updateUser2Test(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
HashMap String, Object map = new HashMap String, Object
map.put("userid",1);
map.put("username","唐三唐昊");
mapper.updateUser2(map);
sqlSession.commit();//增删改必须要提交事务,否则在数据库中就无法查看增删改后的结果
sqlSession.close();
运行结果图
Map传递参数,直接在sql中取出key即可
对象传递参数,直接在sql中取对象的属性即可
只有一个基本类型参数的情况下,可以直接在sql中取到
6.模糊查询
目的:利用模糊查询查询所有姓唐的人
List User getUserLike(String value);
sql代码
select id="getUserLike" resultType="com.tang.pojo.User"
select *from mybatis.user where name like #{value}
/select
测试代码
在Java代码执行的时候,传递通配符% %,不会存在sql注入的问题
//模糊查询
@Test
public void getUserLikeTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
List User userLike = mapper.getUserLike("%唐%");
for(User user: userLike){
System.out.println(user);
sqlSession.close();
在sql拼接中使用通配符,存在sql注入问题
select id="getUserLike" resultType="com.tang.pojo.User"
select *from mybatis.user where name like "%"#{value}"%"
/select
List User userLike = mapper.getUserLike("唐");
两种情况的运行结果
四、配置解析
1.核心配置文件
MyBatis 可以配置成适应多种环境
不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
学会使用配置多套运行环境,比如如下这种方式就可以选择id为test的配置环境,虽然有多套配置环境,但是最终运行的只会是其中一种
configuration
environments default="test"
environment id="development"
transactionManager type="JDBC"/
dataSource type="POOLED"
!-- amp;在xml文件中与符号需要这样来转义--
property name="driver" value="com.mysql.jdbc.Driver"/
property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai amp;useSSL=true amp;useUnicode=true amp;characterEncoding=utf8"/
property name="username" value="root"/
property name="password" value="root123456"/
/dataSource
/environment
environment id="test"
transactionManager type="JDBC"/
dataSource type="POOLED"
!-- amp;在xml文件中与符号需要这样来转义--
property name="driver" value="com.mysql.jdbc.Driver"/
property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai amp;useSSL=true amp;useUnicode=true amp;characterEncoding=utf8"/
property name="username" value="root"/
property name="password" value="root123456"/
/dataSource
/environment
/environments
!-- 每一个mapper.xml都需要在Mybatis核心配置文件中注册--
mappers
mapper resource="com/tang/dao/UserMapper.xml"/
/mappers
/configuration
Mybatis默认的事务管理器就是JDBC,连接池为POOLED
3.属性(properties)
我们可以通过properties属性来实现引用配置文件
这些属性都是可外部配置且可动态替换的,既可以在典型的Java属性文件中配置,也可通过properties元素的子元素来传递【db.properties】
编写一个配置文件
db.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true useUnicode=true characterEncoding=utf8"
username=root
password=root123456
在核心配置文件中引入
!--引入外部配置文件--
properties resource="db.properties"/
然后就可以通过如下的方式去读取db.properties文件里的值
property name="driver" value="${driver}"/
property name="url" value="${url}"/
property name="username" value="${username}"/
property name="password" value="${password}"/
也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:
扫描实体类的包,它的默认别名就为这个类的 类名,首字母小写,大写也行!
如下代码在调用到pojo包下面的类的时候可以直接使用类名的小写字母完成
typeAliases
package name="com.tang.pojo"/
/typeAliases
在实体类比较少的时候使用第一种方式
如果实体类比较多,建议使用第二种
第一种可以DIY起别名,第二种则不行,如果非要改,需要在实体类上增加注解
在实体类上加注解给类名起别名
@Alias("user")
public class User {
5.设置(settings)
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为
6.映射器(mappers)
MapperRegistry:注册绑定我们的Mapper文件;
方式一:【推荐使用】
!-- 每一个mapper.xml都需要在Mybatis核心配置文件中注册--
mappers
mapper resource="com/tang/dao/UserMapper.xml"/
/mappers
方式二:使用class文件绑定注册
mappers
mapper /
/mappers
注意点
7.作用域(Scope)和生命周期
不同作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题
SqlSessionFactoryBuilder
这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了
SqlSessionFactory
SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例
SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
这里面的每一个Mapper,就代表一个具体的业务
五、解决属性名和字段名不一致的问题
数据库中的字段
新建一个项目,拷贝之前的,情况测试实体类字段不一致的情况
public class User {
private int id;
private String name;
private String password;
测试出现问题
select * from mybatis.user where id= #{id}
//类处理器,以上等价于
select id,name,pwd from mybatis.user where id = #{id}
//所以并未查找到pwd字段所以测试结果password为空
解决方法:
起别名
select id="getUserById" parameterType="int" resultType="com.tang.pojo.User"
select id,name,pwd as password from mybatis.user where id = #{id}
/select
resultMap id="UserMap" type="user"
!--column数据库中的字段,property实体类中的属性--
!--id和name属性可以不写,只需要写实体类中与数据库不一样的字段的映射即可--
result column="id" property="id" /result
result column="name" property="name" /result
result column="pwd" property="password" /result
/resultMap
!--select中resultMap的值必须与上面resultMap的id的值相同--
select id="getUserById" resultMap="UserMap"
select * from mybatis.user where id= #{id}
/select
ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了
如果一个数据库操作出现了异常,我们需要排错,日志就是最好的助手
曾经出现异常通常使用:sout、debug来找到异常
现在:使用日志工厂来实现
Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件
log4j.properties
#将等级为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/tang.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
配置log4j日志的实现
settings
setting name="logImpl" value="LOG4J"/
/settings
log4j的使用,直接测试
简单使用
运行结果
1.使用Limit实现分页
//分页
List User getUserByLimit(Map String,Integer map);
接口的xml文件
!-- 分页实现查询--
!-- 这里写user是因为我已经起过别名,所以可简写为user--
select id="getUserByLimit" parameterType="map" resultType="user"
select * from mybatis.user limit #{startIndex},#{pageSize}
/select
@Test
public void getUserByLimit(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
HashMap String, Integer map = new HashMap String, Integer
map.put("startIndex",0);
map.put("pageSize",2);
List User userList = mapper.getUserByLimit(map);
for(User user : userList){
System.out.println(user);
运行结果图
八、使用注解开发
1.面向接口编程
大家之前都学过面向对象编程,也学习过接口,但在真正的开发中,很多时候我们会选择面向接口编程
根本原因 : 解耦 , 可拓展 , 提高复用 , 分层开发中 , 上层不用管具体的实现 , 大家都遵守共同的标准 , 使得开发变得容易 , 规范性更好
关于接口的理解
接口从更深层次的理解,应是定义(规范,约束)与实现(名实分离的原则)的分离。
三个面向区别
面向过程是指,我们考虑问题时,以一个具体的流程(事务过程)为单位,考虑它的实现 .
接口设计与非接口设计是针对复用技术而言的,与面向对象(过程)不是一个问题.更多的体现就是对系统整体的架构
3.Mybatis详细执行流程
4.注解实现CRUD
我们可以再工具类创建的时候实现自动提交事务
public static SqlSession getSqlSession(){
//这里写上true之后在进行增删改之后就会自动提交事务
SqlSession sqlSession = sqlSessionFactory.openSession(true);
return sqlSession;
配置文件中对接口进行注册
mappers
mapper /mapper
/mappers
接口代码
//查询所有用户
@Select("select * from user")
List User getUserList();
//方法存在多个参数,所有的参数前面必须加上@Param注解
//查询指定id的用户
@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);
增删改查的测试类
@Test
public void getUserListTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List User userList = mapper.getUserList();
for (User user : userList) {
System.out.println(user);
@Test
public void getUserBID(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User userById = mapper.getUserById(1);
System.out.println(userById);
sqlSession.close();
@Test
public void addUserTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.addUser(new User(6,"唐银","123"));
sqlSession.close();
@Test
public void updateUserTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.updateUser(new User(1,"汤昊","678"));
sqlSession.close();
@Test
public void deleteUserTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.deleteUser(3);
sqlSession.close();
对user表操作之后的结果图
【关于@Param()注解】
@NoArgsConstructor:无参构造
@AllArgsConstructor:有参构造,写了有参的注解和Data的注解,虽然Data会产生无参,但是在写有参注解的同时无参会消失,因为显示定义有参之后,无参需要手动赋值
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
public interface TeacherMapper {
@Select("select * from teacher where id = #{tid}")
Teacher getTeacher(@Param("tid")int id);
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"
!--核心配置文件--
mapper namespace="com.tang.dao.StudentMapper"
/mapper
TeacherMapper.xml代码
?xml version="1.0" encoding="UTF-8" ?
!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"
!--核心配置文件--
mapper namespace="com.tang.dao.TeacherMapper"
/mapper
public void TeacherMapperTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
Teacher teacher = mapper.getTeacher(1);
System.out.println(teacher);
sqlSession.close();
运行结果图
2.按照查询嵌套处理
目的:查询每个学生及对应老师的信息
mapper namespace="com.tang.dao.StudentMapper"
!--思路:
1.查询所有的学生信息
2.根据查询出来的学生的tid,寻找对应的老师
select id="getStudent" resultMap="StudentTeacher"
-- select s.id,s.name,t.name from student s,teacher t where s.tid = t.id;
select * from student
/select
resultMap id="StudentTeacher" type="Student"
!--因为student和Teacher表中id,和name字段相同,因此这里没必要写映射关系--
!--复杂的属性,我们需要单独处理
对象使用association
集合使用collection
association property="teacher" column="tid" javaType="Teacher" select="getTeacher" /association
/resultMap
select id="getTeacher" resultType="Teacher"
select * from teacher where id=#{id}
/select
/mapper
运行结果图
3.按照结果嵌套处理
目的:查询每个学生及对应老师的信息
!--按照结果嵌套处理--
select id="getStudent2" resultMap="StudentTeacher2"
select s.id sid,s.name snmae,t.id tid,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
result property="name" column="sname" /result
association property="teacher" javaType="Teacher"
result property="name" column="tname" /result
result property="id" column="tid" /result
/association
/resultMap
十一、一对多处理
比如:一个老师拥有多个学生
对于老师而言,就是一对多的关系
1.环境搭建
与之前环境搭建差不多
这里实体类变为
import lombok.Data;
@Data
public class Student {
private int id;
private String name;
private int tid;
import lombok.Data;
import java.util.List;
@Data
public class Teacher {
private int id;
private String name;
//一个老师对应多个学生
private List Student students;
2.按照结果查询
目的:查询每个老师及对应学生的信息
mapper namespace="com.tang.dao.TeacherMapper"
!--按结果嵌套查询--
select id="getTeacher" resultMap="TeacherStudent"
select s.id sid,s.name snmae,t.id tid,t.name tname
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
result property="name" column="tname" /result
!--复杂的属性,我们需要单独处理
对象使用association
集合使用collection
javaType指定属性的类型
集合中的泛型信息,使用ofType获取
collection property="students" ofType="Student"
result property="id" column="sid" /result
result property="name" column="snmae" /result
result property="tid" column="tid" /result
/collection
/resultMap
/mapper
javaType用来指定实体类中属性的类型
ofType用来指定映射到List或者集合中pojo类型,泛型中的约束类型
Mysql引擎
问题描述:一张表,里面有ID自增主键,当insert了17条记录之后,删除了第15,16,17条记录,再把Mysql重启,再insert一条记录,这条记录的ID是18还是15 ?(区分两种数据库引擎)
(1)如果表的类型是MyISAM,那么是18。
因为MyISAM表会把自增主键的最大ID记录到数据文件里,重启MySQL自增主键的最大ID也不会丢失。
(2)如果表的类型是InnoDB,那么是15。
InnoDB表只是把自增主键的最大ID记录到内存中,所以重启数据库或者是对表进行OPTIMIZE操作,都会导致最大ID丢失。
InnoDB底层原理
innoDB 是聚集索引方式,因此数据和索引都存储在同一个文件里。首 先 InnoDB 会根据主键 ID 作为 KEY 建立索引 B+树,如左下图所示,而 B+树的叶子节点存储的是主键 ID 对应的数据,比如在执行 select * from user_info where id=15 这个语句时,InnoDB 就会查询这颗主键 ID 索引 B+树,找到对应的 user_name=Bob。
这是建表的时候 InnoDB 就会自动建立好主键 ID 索引树,这也是为什么 Mysql 在建表时要求必须指定主键的原因。当我们为表里某个字段加索引时 InnoDB 会怎么建立索引树呢?比如我们要给 user_name 这个字段加索引,那么 InnoDB 就会建立 user_name 索引 B+树,节点里存的是 user_name 这个 KEY,叶子节点存储的数据的是主键 KEY。注意,叶子存储的是主键 KEY!拿到主键 KEY 后,InnoDB 才会去主键索引树里根据刚在 user_name 索引树找到的主键 KEY 查找到对应的数据。
索引
问题描述:简单描述MySQL中,索引,主键,唯一索引,联合索引的区别,对数据库的性能有什么影响。
(1)索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。
(2)普通索引(由关键字KEY或INDEX定义的索引)的唯一任务是加快对数据的访问速度。
(3)普通索引允许被索引的数据列包含重复的值,如果能确定某个数据列只包含彼此各不相同的值,在为这个数据索引创建索引的时候就应该用关键字UNIQE把它定义为一个唯一所以,唯一索引可以保证数据记录的唯一性。
(4)主键,一种特殊的唯一索引,在一张表中只能定义一个主键索引,逐渐用于唯一标识一条记录,是用关键字PRIMARY KEY来创建。
(5)索引可以覆盖多个数据列,如像INDEX索引,这就是联合索引。
(6)索引可以极大的提高数据的查询速度,但是会降低插入删除更新表的速度,因为在执行这些写操作时,还要操作索引文件。
1.创建索引
对于查询占主要的应用来说,索引显得尤为重要。很多时候性能问题很简单的就是因为我们忘了添加索引而造成的,或者说没有添加更为有效的索引导致。如果不加索引的话,那么查找任何哪怕只是一条特定的数据都会进行一次全表扫描,如果一张表的数据量很大而符合条件的结果又很少,那么不加索引会引起致命的性能下降。但是也不是什么情况都非得建索引不可,比如性别可能就只有两个值,建索引不仅没什么优势,还会影响到更新速度,这被称为过度索引。
2.复合索引
比如有一条语句是这样的:select * from users where area=’beijing’ and age=22;
如果我们是在area和age上分别创建单个索引的话,由于mysql查询每次只能使用一个索引,所以虽然这样已经相对不做索引时全表扫描提高了很多效率,但是如果在area、age两列上创建复合索引的话将带来更高的效率。如果我们创建了(area, age, salary)的复合索引,那么其实相当于创建了(area,age,salary)、(area,age)、(area)三个索引,这被称为最佳左前缀特性。因此我们在创建复合索引时应该将最常用作限制条件的列放在最左边,依次递减。
3.索引不会包含有NULL值的列
只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时不要让字段的默认值为NULL。
4.使用短索引
对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的 列,如果在前10 个或20 个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。
5.排序的索引问题
mysql查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。
6.like语句操作
一般情况下不鼓励使用like操作,如果非使用不可,如何使用也是一个问题。like “%aaa%” 不会使用索引而like “aaa%”可以使用索引。
7.不要在列上进行运算
select * from users where YEAR(adddate) 2007;
将在每个行上进行运算,这将导致索引失效而进行全表扫描,因此我们可以改成
select * from users where adddate ‘2007-01-01’;
8.不使用NOT IN和操作
NOT IN和操作都不会使用索引将进行全表扫描。NOT IN可以NOT EXISTS代替,id3则可使用id 3 or id 3来代替。
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
测试代码
@Test
public void queryBlogIFTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
map.put("title","java很简单");
List Blog blogs = mapper.queryBlogIF(map);
for (Blog blog : blogs) {
System.out.println(blog);
sqlSession.close();
运行结果图
3.choose(when,otherwise)
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
还是上面的例子,但是策略变为:传入了 “title” 就按 “title” 查找,传入了 “author” 就按 “author” 查找的情形。若两者都没有传入,就返回标记为 featured 的 BLOG(这可能是管理员认为,与其返回大量的无意义随机 Blo。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。