mybatis基础知识
mybatis基础知识
对原生态jdbc程序中问题总结
1.1jdbc程序
使用jdbc查询mysql数据库中用户表的记录
1.2JDBC开发
定义
Connection–>PreparedStatement–>ResultSet
加载数据库驱动–>通过驱动管理类获取数据库链接–>定义sql语句?表示占位符---->获取预处理statement–>设置参数,依次设置占位符表示的值–>向数据库发出sql执行查询,查询出结果集–>遍历查询结果集–>释放资源,按照申请资源的 顺序
1.2问题总结
-
数据库连接,使用时就连接,不使用时就释放,对数据库频繁的连接开启和关闭,造成数据库资源的浪费,影响数据库的性能。
解决方案:数据库连接池
-
讲sql语句硬编码到Java代码中,若sql语句修改,需要重新编译java代码,不利于系统维护
解决方案:将sql语句配置到xml配置文件中
-
向prepareStatement设置参数的时候,对占位符位置和设置参数值,硬编码在java代码中
设想:将sql语句和占位符号以及参数全部配置在xml文件中
-
从resutSet中遍结果集数据时,存在硬编码,将获取表的字段进行硬编码,不利于系统维护
设想:将查询的结果集,自动映射成java对象。
MyBatis框架
2.1MyBatis是什么?
MyBatis是一个持久层框架,是apache下的顶级项目
Mybatis让程序员主要精力放在sql上,通过MyBatis提供的映射方式,自由灵活的生成(半自动化,大部分需要程序员编写sql)满足需要的sql语句
MyBatis可以将向prepareStatement中的输入参数自动进行输入映射,将查询结果集灵活映射成java对象。(输出映射)
2.2MyBatis框架开发步骤以及结构
1.SqlMapConfig.xml(是mybatis的配置文件,名称自定)
配置了数据源,事务等mybatis运行环境
配置了映射文件(配置sql语句)
mapper.xml(映射文件)、mapper.xml、mapper.xml
2.SqlFactionFactory(会话工厂)
作用:创建SqlSession
3.SqlSession(会话),是一个接口,面向用户(程序员)的接口
作用:操作数据库(发出sql增删改查)
4.Executor(执行器),是一个接口(基本执行器、缓存执行器)
作用:SqlSession内部通过执行器操作数据库
mapped statement(底层封装对象)
作用:对操作数据库存储封装。包括sql语句,输入参数、输出结果类型
输入参数类型
java简单类型,hashmap,pojo自定义
输出结果类型
java简单类型,hashmap,pojo自定义
入门程序
3.1需求以及环境
根据用户id(主键)查询用户信息
根据用户名称模糊查询用户信息
添加用户
删除用户
=================================================
Mybatis的jar包,一个包
Mybatis 的操作指南
mysql的驱动包
3.2log4j.properties
classpath下新建文件
步骤 1:添加 Log4J 的 jar 包
因为我们使用的是 Log4J,就要确保它的 jar 包在应用中是可用的。要启用 Log4J,只要将 jar 包添加到应用的类路径中即可。Log4J 的 jar 包可以在上面的链接中下载。
对于 web 应用或企业级应用,则需要将 log4j.jar
添加到 WEB-INF/lib
目录下;对于独立应用,可以将它添加到JVM 的 -classpath
启动参数中。
步骤 2:配置 Log4J
配置 Log4J 比较简单,假如你需要记录这个映射器接口的日志:
package org.mybatis.example;
public interface BlogMapper {
@Select("SELECT * FROM blog WHERE id = #{id}")
Blog selectBlog(int id);
}
在应用的类路径中创建一个名称为 log4j.properties
的文件,文件的具体内容如下:
# Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
添加以上配置后,Log4J 就会记录 org.mybatis.example.BlogMapper
的详细执行操作,且仅记录应用中其它类的错误信息(若有)。
你也可以将日志的记录方式从接口级别切换到语句级别,从而实现更细粒度的控制。如下配置只对 selectBlog
语句记录日志:
log4j.logger.org.mybatis.example.BlogMapper.selectBlog=TRACE
与此相对,可以对一组映射器接口记录日志,只要对映射器接口所在的包开启日志功能即可:
log4j.logger.org.mybatis.example=TRACE
某些查询可能会返回庞大的结果集,此时只想记录其执行的 SQL 语句而不想记录结果该怎么办?为此,Mybatis 中 SQL 语句的日志级别被设为DEBUG(JDK 日志设为 FINE),结果的日志级别为 TRACE(JDK 日志设为 FINER)。所以,只要将日志级别调整为 DEBUG 即可达到目的:
log4j.logger.org.mybatis.example=DEBUG
3.5根据用户id(主键)查询用户信息
3.5.1创建po类(输出的参数类型,类的形式)
字段名和属性名对应(model类)
3.5.2映射文件(User.xml)
映射文件命名:
User.xml(原始ibatis命名),mapper代理开发映射文件名称叫XXXMapper.xm
比如说UserMapper.xml、ItemsMapper.xml
-
parameterType:指定输入参数的类型,这里指定int
-
#{}表示一个占位符号
#{id}:其中的id表示接收输入的参数,参数名称是id,如果输入参数是简单类型,#{}中的参数名可以任意,可以value或其他名称${}表示拼接字符串,将接收的内容不加任何修饰拼接在sql中,不建议使用?
-
resultType:指定sql输出结果所映射的Java对象
在映射文件中配置sql语句
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="">
<!-- 在映射文件中配置很多sql语句-->
<!-- 通过id查询用户id-->
<!-- 通过select执行数据库查询
id:标识映射文件的sql,称为statement的id
将sql语句封装到mappedStatement对象中,所以将id称为statement的id-->
<!-- parameterType:指定输入参数的类型,这里指定int-->
<!-- #{}表示一个占位符号
#{id}:其中的id表示接收输入的参数,参数名称是id,
如果输入参数是简单类型,#{}中的参数名可以任意,可以value或其他名称
resultType:指定sql输出结果所映射的Java对象-->
<select id="findUserById" parameterType="int" resultType="arraylist">
SELECT * FROM test WHERE id=#{id}
</select>
</mapper>
============================================================
附:mapper的namespace属性
============================================================
在mybatis中,映射文件中的namespace是用于绑定Dao接口的,即面向接口编程。
**当你的namespace绑定接口后,你可以不用写接口实现类,mybatis会通过该绑定自动帮你找到对应要执行的SQL语句,**如下:
假设定义了IArticeDAO接口
public interface IArticleDAO
{
List<Article> selectAllArticle();
}
对于映射文件如下:
<mapper namespace="IArticleDAO">
<select id="selectAllArticle" resultType="article">
SELECT t.* FROM T_article t WHERE t.flag = '1' ORDER BY t.createtime DESC
</select>
请注意接口中的方法与映射文件中的SQL语句的ID一一对应 。
则在代码中可以直接使用IArticeDAO面向接口编程而不需要再编写实现类。
=============================================================
3.5.3在SqlMapConfig.xml加载映射文件
<mappers>
<mapper resource="sqlmap/User.xml"/>
</mappers>
=============================================================
附:关于Maven项目中无法加载MyBatis映射文件解决办法
=============================================================
还有另外一种解决方法,就是将映射文件放在resources/sqlmapping文件夹下,然后在mybatis-config.xml中进行如下导入:(需要设置resource文件夹)
<mappers>
<mapper resource="sqlmapping/UserMapper.xml"/>
</mappers>
=============================================================
3.5.4程序的编写
创建会话工厂,利用会话工厂获得SqlSession,利用SqlSession执行
- selectone表示查询出一条记录的映射
- selectList表示查询List对象(多条结果)
- sqlSession.selectOne(“MybatisTest.getName”, 12);中第一个参数:映射文件中statement的id,等于=namespace+“0”+statement的id, 第二个参数: 指定和映射文件中所匹配的parameterType类型的参数(输入参数)
===========================================
SqlSessionFactory sqlSessionFactory= new SqlSessionFactoryBuilder().build(inputStream);
===========================================
**创建会话工厂:**加载配置文件,得到文件流,传入会话工厂的build方法
=======================================================
//mybatis配置文件
String resource = “mybatis_config.xml”;
//得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
=======================================================
@Test
public void find() throws IOException {
//mybatis配置文件
String resource = "mybatis_config.xml";
//得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建会话工厂,传入mybatis文件的配置信息
SqlSessionFactory sqlSessionFactory= new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂获得SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//通过SqlSession操作数据库
/**
* 第一个参数:映射文件中statement的id,等于=namespace+"0"+statement的id
* 第二个参数: 指定和映射文件中所匹配的parameterType类型的参数(输入参数)
*/
Userid userid=sqlSession.selectOne("MybatisTest.getName", 12);
System.out.println(userid);
//释放资源,最好使用try-catch 的finally语句
}
- **#{}表示一个占位符,**可以是简单类型,pojo,hashmap
- **${}表示拼接字符串,将接收的内容不加任何修饰拼接在sql中。**如果传入参数为简单类型,括号内只能写value
使用${}会有安全隐患,如sql注入
mybatis开发dao
SqlSession使用范围
4.1.1 SqlSessionFactoryBuilder
通过SqlSessionFactoryBuilder创建会话工厂SqlSessionFactory
将SqlSessionFactory当作工具类即可,不需要使用单例管理SqlSessionFactoryBuilder
4.1.2 SqlSessionFactory
通过SqlSessionFactory创建SqlSession,使用单例模式管理sqlSessionFactory(工厂一旦创建,使用一个实例)
将来mybatis和spring整合后,使用单例模式管理sqlSessionFactory
4.1.3 SqlSession
SqlSession是一个面向用户(程序员)的接口
SqlSession中提供了很多操作数据库的方法:如:selectOne,selectList
SqlSession线程不安全,在SqlSession实现类中除了有实现接口中的方法(操作数据库)还有数据域属性。
SqlSession最佳应用场合在方法体内,定义局部变量使用。
4.2 原始dao开发方法(程序员需要写dao接口和dao实现类)
4.2.1 思路
程序员需要写dao接口和dao实现类
向dao中注入SqlSessionFactory,在方法体内通过SqlSessionFactory创建SqlSession
4.2.2 内容
编写dao
public interface MyBatisTest {
List<Object> getName(Integer id);
void insertUser();
void deleteUser();
void updateId();
}
编写实现类
public class TestDao implements MyBatisTest{
public SqlSessionFactory sqlSessionFactory;
public TestDao(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
}
@Override
public List<Object> getName(Integer id) {
SqlSession sqlSession=sqlSessionFactory.openSession();
List<Object> userids=sqlSession.selectOne("MybatisTest.getName",id);
// 释放资源
sqlSession.close();
return userids;
}
@Override
public void insertUser() {
}
@Override
public void deleteUser() {
}
@Override
public void updateId() {
}
}
4.3 mapper代理的方法(程序员只需要mapper接口(相当于dao接口))
4.3.1思路
程序员需要开发mapper接口
程序员还要编写mapper.xml文件
程序员只需要编写mapper接口(相当于dao接口)
mybatis自动生成mapper接口实现类代理对象
4.3.2开发规范:
现有默认开发模式就是mapper
- mapper对应的id是类
- 语句对应的id是方法名
- mapper方法的输入类型和mapper.xml中statement的paramentType指定的类型一样
- mapper方法的返回类型和mapper.xml中statement的resultType指定的类型一样
自动注入Session工厂类,定义UserMapper(dao)类,使用sqlSession获取mapper类
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
MyBatis增删改查
=============================================
注意!!!sql语句不需要写分号
==============================================
查询
映射文件
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="">
<!-- 在映射文件中配置很多sql语句-->
<!-- 通过id查询用户id-->
<!-- 通过select执行数据库查询
id:标识映射文件的sql,称为statement的id
将sql语句封装到mappedStatement对象中,所以将id称为statement的id-->
<!-- parameterType:指定输入参数的类型,这里指定int-->
<!-- #{}表示一个占位符号
#{id}:其中的id表示接收输入的参数,参数名称是id,
如果输入参数是简单类型,#{}中的参数名可以任意,可以value或其他名称
resultType:指定sql输出结果所映射的Java对象-->
<select id="findUserById" parameterType="int" resultType="arraylist">
SELECT * FROM test WHERE id=#{id}
</select>
</mapper>
selectOne
返回一个结果
selectList
返回结果集
=============================================================
添加
映射文件
<!-- 添加用户,
parameterType:指定输入参数类型是pojo(包括用户信息)
#{}中指定pojo的属性名,接收到pojo对象的属性值,mybatis通过OGNL来获取对象的属性值
-->
<insert id="insertUser" parameterType="model.Userid">
INSERT INTO test(id, name) value (#{id},#{name})
</insert><!-- 添加用户,
parameterType:指定输入参数类型是pojo(包括用户信息)-->
<insert id="insertUser" parameterType="model.Userid">
INSERT INTO test(id, name) value (#{id},#{name});
</insert>
获取sqlSession后需要提交事务:sqlSession.commit();整合spring后不需要
insert
自增的不需要加入sql语句
若想返回刚刚插入记录的自增主键:
SelectKey标签
自增主键
<!-- 添加用户,
parameterType:指定输入参数类型是pojo(包括用户信息)
#{}中指定pojo的属性名,接收到pojo对象的属性值,mybatis通过OGNL来获取对象的属性值
SELECT LAST_INSERT_ID():得到刚刚insert进去的主键值,只适用自增主键
keyProperty:将查询到的主键设置到parameterType指定的对象的哪个属性
order:SELECT LAST_INSERT_ID()执行顺序,相对于insert语句来说它的执行顺序
-->
<insert id="insertUser" parameterType="model.Userid">
INSERT INTO test(id, name) value (#{id},#{name})
<selectKey keyProperty="id" order="AFTER" resultType="Intenger">
SELECT LAST_INSERT_ID()
</selectKey>
</insert>
非自增主键
使用uuid()替换
删除
映射文件
<delete id="deleteUser" parameterType="integer">
DELETE FROM test WHERE id =#{id}
</delete>
delete方法
更新
映射文件
<update id="updateId" parameterType="model.Userid">
UPDATE test SET name=#{name} WHERE id=#{id}
</update>
update方法
输入映射
通过parameterType指定输入参数的类型,类型可以是简单类型、hashmap、pojo的包装类型
6.1 传递pojo的包装对象
6.1.1 需求
完成用户信息的综合查询,需要传入查询条件很复杂(可能包括用户信息、其他信息,比如商品、订单)
6.1.2 定义包装类型pojo
针对上面的条件,建议使用自定义包装的pojo
在包装类型的pojo中将复杂的查询条件包装进去。
在po包中创建Vo类
vo po pojo
6.1.3 利用包装类型
视图层model UserVo
编写视图层的vo时可以直接在构建类,类中定义一个或几个基础对象
package model;
public class UserIdQueryVo {
/**
* 在这里写额外的信息,如订单等等
*/
/**
* 用户的基础信息
*/
private Userid userid;
public Userid getUserid() {
return userid;
}
public void setUserid(Userid userid) {
this.userid = userid;
}
}
6.1.3映射文件(mapper.xml)
在UserMapper.xml中定义用户信息综合查询(查询条件复杂,通过高级查询进行复杂关联查询).
7. 输出映射
7.1 resultType
使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。
如果查询出来的列名和pojo中的属性名全不一致,没有创建pojo对象。
只要查询出来的列名和pojo中的属性有一个一致,就会创建pojo对象。
7.1.1 .1 需求
用户信息的综合查询列表总数,通过查询总数和上边的用户综合查询列表才可实现分页。
7.1.1.2 实现
<select id="findUserCount" parameterType="model.UserIdQueryVo" resultType="int">
SELECT COUNT(*) FROM test WHERE test.name= #{id}
</select>
7.1.1.3 总结
查询出来的结果集只有一行或一列,可以使用简单类型进行输出映射
7.1.2 输出pojo对象和pojo列表
不管输出pojo单个对象还是 一个列表(list中包括pojo),在mapper.xml中resultType指定的类型是一样的。
在mapper.java指定的方法返回值类型不一样
- 输出单个pojo对象,方法返回值是单个对象类型
- 输出多个pojo对象,方法返回值是List对象List
动态的代理对象中是根据mapper方法的返回值类型确定调用selectOne还是SelectList
7.2 resultMap
mybatis中使用resultMap完成高级输出结果映射。
7.2.1 resultMap的用法
如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间作一个映射关系
- 定义resultMap
- 使用resultMap作为statement的输出映射类型
7.2.2 将下面的sql使用User完成映射
SELECT id id_ ,username username_ FROM WHERE id=#{value}
user类中属性名和上面查询列名不一致
<!--将SELECT id id_ ,username username_ FROM WHERE id=#{value} 和User类中的属性做一个映射关系
type:resultMap最终映射的java类型,可以使用别名
id:对resultMap的唯一标识
-->
<resultMap id="userResultMap" type="model.Userid">
<!-- id表示查询结果集中的唯一标识
column标识查询出的列名
property:type指定的pojo类型中的属性名-->
<!-- 最终resultMap对Column和property作映射关系-->
<id column="id_" property="id"/>
<!-- 对普通列的定义-->
<!-- result:对普通映射名的定义-->
<!-- column:查询出来的列名-->
<!-- property:type指定的pojo类型的属性名-->
<!-- 最终resultMap对Column和property作映射关系
如果这个resultMap在其他的mapper文件,前面需要加namespace
-->
<result column="name_" property="name"/>
</resultMap>
<select id="findUserCount" parameterType="model.UserIdQueryVo" resultMap="userResultMap">
SELECT COUNT(*) FROM test WHERE test.name= #{id}
</select>
mybatis支持的别名
别名 | 映射的类型 |
---|---|
_byte | byte |
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
map | Map |