mybatis的maven依赖包:
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>x.x.xversion>
dependency>
概念理解:
每个基于MyBatis的应用都是以一个SqlSeesionFactory的实例为核心的,该实例可用SqlSessionFactoryBuilder获得,这个SSFB可以通过XML配置文件或预先配置的Configuration实例构建。
方法流程:
xml配置文件:
xml配置文件包含核心设置,包括数据库连接实例、决定事务作用域和控制方式的事务管理器,先给个简单示例:
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
mappers>
configuration>
mapper中包含一组映射器,这些映射器包含了SQL代码和映射定义信息。
使用类路径下的资源文件进行配置并获取SqlSessionFactory:
这三行还是比较固定的
// 文件路径
String resource = "org/mybatis/example/mybatis-config.xml";
// 利用资源获得输入流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 根据输入流获取SSF
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
方法流程:
使用java代码写的,具体没看懂,然而因为要用一些高级映射,所以还是会用到xml
获取代码:
DataSource dataSource = BlogDataSourceFactory.getBlogDataSource();
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(BlogMapper.class);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
SqlSession session = sqlSessionFactory.openSession()
注意:使用依赖注入可以直接忽略生命周期(这块和Spring挂钩)。
类 | 生命周期 | 最佳作用域 |
---|---|---|
SqlSessionFactoryBuilder | 这个类可以实例化、使用、丢弃,一旦创建了SqlSessionFactory就不需要这个东西了 | 最好是作为一个局部变量,方法作用域 |
SqlSessionFactory | 一旦被创建就一直运行,没有任何理由丢弃或重建另一个实例,也不应重复创建多次 | 应用作用域 |
SqlSession | 每个线程都有自己的SqlSession实例,SqlSession实例不是线程安全的,不可共享 | 请求或方法作用域,不可放在静态域中,不可放在托管域中,使用应立刻关闭,关闭应放到finally中 |
映射器实例 | 在调用他们的方法中被获取,使用完毕后即可丢弃,不需要显示地关闭 | 方法作用域 |
官方建议:
方法作用域就是放在try里面那样子。
try (SqlSession session = sqlSessionFactory.openSession()) {
BlogMapper mapper = session.getMapper(BlogMapper.class);
// 你的应用逻辑代码
}
作用:
两种命名规则:
com.mypackage.MyMapper.selectAllThings
selectAllThings
。如果全局唯一可以如此,如果不唯一,则要用全名。方法流程:
父工程maven配置文件:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.itgroupId>
<artifactId>Mybatis_learnartifactId>
<packaging>pompackaging>
<version>1.0-SNAPSHOTversion>
<modules>
<module>mybatis-01module>
modules>
<dependencies>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.47version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.2version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
dependencies>
<build>
<resources>
<resource>
<directory>src/main/resourcesdirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>falsefiltering>
resource>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>falsefiltering>
resource>
resources>
build>
project>
工具类:
public class utils {
public static SqlSessionFactory sqlSessionFactory;
static {
try{
// 文件路径
String resource = "config.xml";
// 利用资源获得输入流, 这里有个异常
InputStream inputStream = Resources.getResourceAsStream(resource);
// 根据输入流获取SSF
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (Exception o){
o.printStackTrace();
}
}
public SqlSession geSS(){
return sqlSessionFactory.openSession();
}
}
数据库记录对应的实体类:
该类和数据库记录相对应, 类中的私有成员变量名应和数据库中的相同。
当从数据库中取出数据的时候,就用该类接受。
// 实体类
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;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", 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;
}
}
核心配置文件:
管理事务、数据库连接、映射相关内容。
注意的点:
&
/
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&userUnicode=true&characterEncoding=gbk"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="it/dao/BlogMapper.xml"/>
mappers>
configuration>
资源过滤:
maven默认只能读取resources中的xml,使用下面的build,可以将检索范围扩大。
注意:
<build>
<resources>
<resource>
<directory>src/main/resourcesdirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>truefiltering>
resource>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>truefiltering>
resource>
resources>
build>
流程:
接口类:
需要实现的Sql功能的方法都在这里
// 得是个接口,参数和返回类型要和sql语句匹配
public interface BlogMapper {
// 注释和xml不可共存
// @Select("SELECT * FROM mybatis.user where id = #{id}")
User getUser(int id);
// insert, 参数为对应class
int doInsert(User user);
// update,参数为对应class
int doUpdate(User user);
// delete, 参数随意
int doDelete(int id);
// map用法,key为String类型,value为Object类型
User getUserMap(Map<String, Object> map);
// 模糊查询
List<User> getUserMH(String string);
}
配置文件绑定
namespace和接口的绑定、接口类中的方法和xml中的SQL语句的绑定。
注意:
List
,那么这里也要是E
<mapper namespace="it.dao.BlogMapper">
<select id="getUser" resultType="it.User">
select * from mybatis.user where id = #{id}
select>
<insert id="doInsert" parameterType="it.User">
insert into mybatis.user(id, Name, pwd) value (#{id}, #{name}, #{pwd});
insert>
<update id="doUpdate" parameterType="it.User">
update mybatis.user set Name=#{name}, pwd=#{pwd} where id=#{id};
update>
<delete id="doDelete" parameterType="int">
delete from mybatis.user where id=#{id};
delete>
<select id="getUserMap" parameterType="map" resultType="it.User">
select * from mybatis.user where id=#{iddd};
select>
<select id="getUserMH" resultType="it.User">
select * from mybatis.user where name like #{value};
select>
mapper>
测试类:
public class dot {
public static void main(String[] args) {
utils g = new utils();
SqlSession sqlSession = g.geSS();
// 方法一
// 获取映射器
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
// 调用映射器方法
User user = mapper.getUser(1);
System.out.println(user.toString());
int jojo = mapper.doUpdate(new User(1, "jojo", "1234"));
System.out.println(jojo);
mapper.doDelete(2);
mapper.doInsert(new User(5, "ll","123"));
sqlSession.commit();
sqlSession.close();
// 方法二
// User user1 = sqlSession.selectOne("it.dao.BlogMapper.getUser", 2);
// System.out.println(user1.toString());
// sqlSession.close();
}
@Test
public void testMap(){
utils g = new utils();
SqlSession sqlSession = g.geSS();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
// 此处要定义一个map
Map<String, Object> map =new HashMap<String, Object>();
map.put("iddd",1);
User userMap = mapper.getUserMap(map);
System.out.println(userMap.toString());
// 模糊查询
System.out.println("-------------");
List<User> list = mapper.getUserMH("%李%");
for( User use: list){
System.out.println(use.toString());
}
}
}
这两个在上面的代码中有体现
Map:
模糊查询:
多个环境的必要性:尽管可以配置多个环境,但每个SqlSessionFactory实例只能选择一种环境,即每个数据库对应一个SqlSessionFactory实例。
环境配置文件:
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="..." value="..."/>
</transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
生成时指定环境:
这里的environment
使用的是id
属性
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, properties);
生成时不指定环境:
使用default
指定的环境
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, properties);
config.properties文件:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&userUnicode=true&characterEncoding=gbk
涉及到properties部分的配置代码:
<properties resource="config.properties">
<property name="username" value="root"/>
<property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/>
properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password:1234}"/>
dataSource>
environment>
environments>
properties读取优先级:
注意点:
三种起别名方式:
xml中代码:
<typeAliases>
<typeAlias alias="user" type="it.User"/>
<package name="it"/>
typeAliases>
实体类中代码:
// 实体类
@Alias("user")
public class User {}
优先级:typeAlias > 注解 > package
三种方式:
注意:
xml文件代码:
<mappers>
<mapper resource="it/dao/BlogMapper.xml"/>
<mapper class="it.dao.BlogMapper"/>
<package name="it.dao"/>
mappers>
问题描述:接受数据库数据的类中的成员变量名和数据库的字段不一样
出现问题原因:
一般情况下,MyBatis会自动创建一个ResultMap,在基于属性名映射column到实体类的属性上,没匹配就会出现null。
最简单最笨的解决方式:
就是sql的起别名:
select id, name, pwd as passowrd from user where id = #{id}
使用方法:
把ResultType换成ResultMap
两种名称:
id name pwd
id name password
结果集映射:
<!--结果集映射-->
<resultMap id="UserMap" type="User">
<!--column数据库中的字段,property实体类中的属性-->
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="pwd" property="password"/>
</resultMap>
<select id="getUserById" resultMap="UserMap">
select * from mybatis.user where id = #{id}
</select>
resultMap
元素是 MyBatis 中最重要最强大的元素ResultMap
的设计思想是,对于简单的语句根本不需要配置显式的结果映射,而对于复杂一点的语句只需要描述它们的关系就行了。日志的作用:如果一个数据库操作,出现了异常,需要排错,就要用日志。
日志类型:
1. 导入Log4j的maven:
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
2. log4j.properties:
属性设置文件,放到resource
中,名字乱写会报错
#将等级为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/kuang.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
3. mybatis配置文件中编写settings
:
<settings>
<setting name="logImpl" value="LOG4J"/>
settings>
4. 实例化日志对象:
参数为当前类的class
static Logger logger = Logger.getLogger(dot.class);
5. 日志的级别:
public void testlog4j(){
logger.info("info");
logger.debug("debug");
logger.error("error");
}
配对问题:
好像是只要在配置文件中声明了setting
,然后在这个项目里不管调用什么函数都会按照日志配置文件操作。
至于Logger加载的class有啥用,现在还不知道,可能是监控这个类的所有行为?
sql
分页基础知识:
// 从startIndex起,每页放pageSize个
select * from user limit startIndex, pageSize;
// 从第4个起,一直到最后,是个bug,被修复了
// select * from user limit 4, -1;
// 只有一个参数,就是从0开始到n
select * from user limit n;
步骤:
List<User> getPage(Map<String, Integer> map);
<select id="getPage" parameterType="map" resultMap="userMap">
select * from mybatis.user limit #{startIndex}, #{pageSize}
select>
public void testLimi(){
utils g = new utils();
SqlSession sqlSession = g.geSS();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
// 设置key和value
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("startIndex", 1);
map.put("pageSize", 2);
List<User> page = mapper.getPage(map);
for (User user : page){
System.out.println(user.toString());
}
sqlSession.close();
}
这个方法不需要sql
步骤:
List<User> getUserByRowBounds();
<select id="getUserByRowBounds" resultMap="UserMap">
select * from mybatis.user
select>
@Test
public void getUserByRowBounds(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//RowBounds实现
RowBounds rowBounds = new RowBounds(1, 2);
//通过Java代码层面实现分页
List<User> userList = sqlSession.selectList("com.kuang.dao.UserMapper.getUserByRowBounds",null,rowBounds);
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
根本原因:解耦,可拓展,提高复用,分成开发中,上层不用管具体的实现,大家都遵守共同的标准,使得开发变得容易,规范性更好。
关于接口的理解:
本质:主要应用反射
底层:动态代理
使用方法:
接口:
public interface BlogMapper {
@Select("select * from mybatis.user where id=#{uid}")
public User getUser(@Param("uid") int id);
// 做不到参数map
@Insert("Insert into mybatis.user(id, name, pwd) values(#{id},#{name},#{password})")
public int doInsert(User user);
@Update("update user set name=#{name}, pwd=#{password} where id=#{id}")
public int doUpdate(User user);
@Delete("delete from user where id=#{id}")
public int doDelete(int id);
}
核心配置文件变化:
绑定一个接口类
<mappers>
<mapper class="it.dao.BlogMapper"/>
mappers>
测试类:
@Test
public void testJunit(){
utils g = new utils();
SqlSession sqlSession = g.geSS();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
System.out.println("查询:");
User user1 = mapper.getUser(1);
System.out.println(user1.toString());
mapper.doInsert(new User(7, "hhh", "111"));
mapper.doDelete(5);
mapper.doUpdate(new User(4,"hxh","22"));
}
注意:
ssf.openSession(true)
设置为true可自动提交。@Param("id")
,sql中的参数名要和Param的一样。使用步骤:
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.10version>
<scope>providedscope>
dependency>
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
// 名字和数据库里的一样
private int id;
private String name;
private String password;
}
流程:
resultMap
并自定义map。type
设置为原本应该接受的类型,后面的变动的地方用association
或collection
来改变,javaType
是想要的类型,再用一个select
从另一个sql
中获取信息。select
的参数,resultType
为想要的类型。思路:
全选出来,先选出来的结果要被接收,然后在第一次输出的结果中再去查找。
代码:
// 查询所有的学生信息和对应的老师的信息
public List<Student> getStudent();
<select id="getStudent" resultMap="StudentTeacher">
select * from mybatis.student
select>
<resultMap id="StudentTeacher" type="Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
resultMap>
<select id="getTeacher" resultType="Teacher">
select * from mybatis.teacher where id=#{tid}
select>
流程:
resultMap
,不过sql
语句可以写成想要的那种resultMap
的修改,来让结果拟合之前的sql
语句思路:
代码:
public List<Student> getStudent2();
<select id="getStudent2" resultMap="StudentTeacher2">
select s.id sid, s.name sname, t.name tname
from mybatis.student s, mybatis.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>
两种方法,如果结果是集合,resultMap
中应用collection
。
第一种方式:
<select id="getStudentsByTeacher2" resultMap="StuTeacher">
select * from mybatis.teacher where id=#{tid}
select>
<resultMap id="StuTeacher" type="Teacher">
<result property="id" column="id"/>
<result property="name" column="name"/>
<collection property="students" javaType="ArrayList" ofType="Student" select="getStudents" column="id"/>
resultMap>
<select id="getStudents" resultType="Student">
select * from mybatis.student where tid=#{tid}
select>
第二种方式:
<select id="getStudentsByTeacher" resultMap="Students">
select s.name sname, s.id sid, 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="Students" type="Teacher">
<result property="name" column="tname"/>
<result property="id" column="tid"/>
<collection property="students" ofType="Student">
<result property="name" column="sname"/>
<result property="id" column="sid"/>
collection>
resultMap>
小结:
比较好理解,有几个关键方法:
and
和or
接口类:
public interface BlogMapper {
// 不要乱设置参数名
int InsertBlog(Blog blog);
// if查找
List<Blog> getByIf(Map<String,Object> map);
// 测试where
List<Blog> getUseWhere(Map<String,Object> map);
// 测试choose
List<Blog> getUseChoose(Map<String,Object> map);
// 测试set
int doUpdate(Map<String, Object> map);
}
<mapper namespace="it.dao.BlogMapper">
<insert id="InsertBlog" parameterType="Blog">
insert into mybatis.blog(id, title, author, create_time, views)
values (#{id}, #{title}, #{author}, #{createTime}, #{views})
insert>
<select id="getByIf" parameterType="map" resultType="Blog">
select * from mybatis.blog where 1=1
<if test="author !=null ">
and author=#{author}
if>
<if test="views !=null ">
and views=#{views}
if>
select>
<select id="getUseWhere" parameterType="map" resultType="Blog">
select * from mybatis.blog
<where>
<if test="author !=null ">
and author=#{author}
if>
<if test="views !=null ">
and views=#{views}
if>
where>
select>
<select id="getUseChoose" parameterType="map" resultType="Blog">
select * from mybatis.blog
<where>
<choose>
<when test="title != null">
title=#{title}
when>
<when test="author != null">
and author=#{author}
when>
<otherwise>
views=2
otherwise>
choose>
where>
select>
<update id="doUpdate" parameterType="map">
update mybatis.blog
<set>
<if test="title != null">
title=#{title},
if>
<if test="views != null">
views=#{views}
if>
set>
where author=#{author}
update>
mapper>
测试类:
@Test
public void testIf(){
utils uu = new utils();
SqlSession sqlSession = uu.geSS();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
Map<String, Object> map = new HashMap<String, Object>();
List<Blog> byIf = mapper.getByIf(map);
System.out.println(byIf);
System.out.println("使用了条件");
map.put("author","jojo");
List<Blog> byIf2 = mapper.getByIf(map);
System.out.println(byIf2);
}
@Test
public void testWhere(){
utils uu = new utils();
SqlSession sqlSession = uu.geSS();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
Map<String, Object> map = new HashMap<String, Object>();
List<Blog> useWhereNo = mapper.getUseWhere(map);
System.out.println(useWhereNo);
System.out.println("使用map=====================");
map.put("author","jojo");
List<Blog> useWhere = mapper.getUseWhere(map);
System.out.println(useWhere);
}
@Test
public void testChoose(){
utils uu = new utils();
SqlSession sqlSession = uu.geSS();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
Map<String, Object> map = new HashMap<String, Object>();
System.out.println("空的,views=2的数据:");
List<Blog> choose1 = mapper.getUseChoose(map);
System.out.println(choose1);
System.out.println("title=java, author=kiruto的情况=================");
map.put("title", "java");
map.put("author", "kiruto");
List<Blog> choose2 = mapper.getUseChoose(map);
System.out.println(choose2);
}
@Test
public void testSet(){
utils uu = new utils();
SqlSession sqlSession = uu.geSS();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
Map<String, Object> map = new HashMap<String, Object>();
map.put("author", "jojo");
map.put("title", "change");
mapper.doUpdate(map);
sqlSession.commit();
sqlSession.close();
}