首发日期:2018-10-31python
与JDBC的对比中,MyBatis是基于ORM的,自然要比JDBC强,基于ORM使得MyBatis具备查询的数据能够自动封装到对象中的等好处,而JDBC须要手动编码的位置就较多了(就算是使用DButils,你也须要使用定义不一样的方法来给不一样的持久类赋值。)。mysql
在互联网应用程序开发中,对于存储过程和复杂的SQL,Hibernate并无很好地去处理,因此它比较难提高性能(并非说不能,而是耗费心思较多),没法知足高并发和高响应的需求(若是要强行优化,又破坏了Hibernate的全自动ORM设计)。git
与之对应的,Mybatis能够说是基于SQL的,它须要咱们去自定义SQL,那么咱们能够根据须要去设计和优化SQL,这种可针对SQL的优化的持久层框架,恰巧符合高并发和高响应的互联网应用程序开发开发需求。github
1.首先要下载依赖包https://github.com/mybatis/mybatis-3/releasessql
2.建立普通javase工程,导入依赖包(我这里使用mybatis-3.4.5 ):数据库
3.建立持久类和建立数据表:持久类是用于封装从数据库中返回的结果,能够说持久类的对象就是数据库记录在java中的实体(这里约定数据表的列名与持久类的属性名一致)。apache
package work.pojo; public class User { private Integer id; private String name; private Integer age; //省略setter,getter,toString }
create table user( id int primary key auto_increment, name varchar(20), age int );
4.在持久类User.java同级目录下建立映射文件user.xml:这个映射文件的意义是用来定义sql语句,使得咱们能够在代码中调用sql语句【不一样类的标签订义不一样类的SQL,id用于标识SQL语句,parameterType是传入SQL语句的参数,resultType定义了返回结果的类型(这里因为表字段和类属性名一致,查询的记录的各个值会自动赋给对象)】设计模式
<?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="user"> <!--id用于标识SQL,parameterType是传给SQL的参数的类型,resultType是返回结果的类型 --> <select id="getUserById" parameterType="int" resultType="work.pojo.User" > <!-- 使用#{}来传入参数 --> SELECT * FROM USER WHERE id = #{id} </select> </mapper>
5.配置mybatis配置文件,这里命名为mybatis-config.xml
。配置文件的意义是配置MyBatis的运行设置,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> <environments default="development"> <!-- environment用来定义数据库链接环境,environments用来定义多个environment --> <environment id="development"> <!-- transactionManager配置事务管理,使用jdbc事务管理 --> <transactionManager type="JDBC" /> <!-- dataSource配置数据库链接池 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/mybatis" /> <property name="username" value="root" /> <property name="password" value="123456" /> </dataSource> </environment> </environments> <mappers> <!-- 导入映射文件,这样MyBatis才能管理到SQL语句 --> <mapper resource="work/pojo/user.xml"/> </mappers> </configuration>
6.编写测试方法:
配置文件配完后,要想经过mybatis操做数据库,那么就须要使用SqlSessionFactoryBuilder、SqlSessionFactory和SqlSession几个对象。
@Test public void test1() throws IOException { // 建立SqlSessionFactoryBuilder对象 SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder(); // 经过Mybatis包的Resources类来将配置文件转成输入流 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); // 加载配置文件输入流,建立SqlSessionFactory对象 SqlSessionFactory sqlSessionFactory = sfb.build(inputStream); // sqlSessionFactory建立SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); // 执行查询,第一个参数是映射文件中定义的SQL的id名,第二个参数是传给SQL的参数。 User user = sqlSession.selectOne("getUserById", 1); // 输出查询结果 System.out.println(user); // 释放资源 sqlSession.close(); }
这里给一下文件结构、数据表数据和测试结果。
文件结构:
数据表数据:
测试结果:User [id=1, name=沙僧, age=18]
上面演示了MyBatis的使用,相信你对MyBatis已经有了一个初步的了解,下面将对各个部分的知识进行讲解。
1.核心组件【关于SqlSessionFactoryBuilder这些对象,以及了解Mybatis的运行流程】
2.mybatis配置文件的配置【关于数据库链接之类的配置】
3.映射文件的配置【关于SQL语句的定义方式】
以传入一个配置文件的字节输入流对象为例,MyBatis提供了一个Resource类,它能够很方便地将配置文件转成输入流:
// 建立SqlSessionFactoryBuilder对象 SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder(); // 经过Resources类来将配置文件转成输入流,Resources是mybatis提供的 InputStream inputStream=Resources.getResourceAsStream("mybatis-config.xml"); // 加载配置文件输入流,建立SqlSessionFactory对象 SqlSessionFactory sqlSessionFactory = sfb.build(inputStream);
sqlSession.commit();
。// sqlSessionFactory建立SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); //开启自动提交,默认增、删、改是不自动提交的 //SqlSession sqlSession = sqlSessionFactory.openSession(true);
SqlSession的做用相似于JDBC中的Connection对象。
使用示例:
SqlSession sqlSession = sqlSessionFactory.openSession(); User user = new User(); user.setName("铁头娃"); user.setAge(4); //发送sql sqlSession.insert("insertUser", user); //提交事务 sqlSession.commit(); // 释放资源 sqlSession.close();
若是这个接口遵循了Mapper的开发规范,而且有对应的映射文件,那么sqlSession调用getMapper方法能够获取一个mapper对象,mapper对象能够直接调用接口方法来执行映射文件中对应的SQL语句。
sqlSession.getMapper(某个接口.class);
功能:
Mapper也能够发送SQL,调用Mapper接口中的方法就至关于sqlSession调用映射文件中的SQL。【这样的调用是彻底面向对象的,如今广泛用这种。】
SqlSession sqlSession = sqlSessionFactory.openSession(); //发送sql UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.getUserById(1); //User user = sqlSession.selectOne("getUserById", 1); //原方式 System.out.println(user); // 释放资源 sqlSession.close();
稍微了解了一下核心组件以后,再回头看一下以前的代码:
@Test public void test1() throws IOException { // 建立SqlSessionFactoryBuilder对象 SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder(); // 经过Mybatis包的Resources类来将配置文件转成输入流 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); // 加载配置文件输入流,建立SqlSessionFactory对象 SqlSessionFactory sqlSessionFactory = sfb.build(inputStream); // sqlSessionFactory建立SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); // 执行查询,第一个参数是映射文件中定义的SQL的id名,第二个参数是传给SQL的参数。 User user = sqlSession.selectOne("getUserById", 1); // 输出查询结果 System.out.println(user); // 释放资源 sqlSession.close(); }
咱们如今先来了解一些映射文件的配置,也就是映射文件里面所谓的SQL语句之类的怎么写。这里了解了映射文件怎么配置以后,你能够先使用sqlSession来执行SQL体验一下其中的意义的。
SqlSession sqlSession = sqlSessionFactory.openSession(); User user = new User(); user.setName("铁头娃"); user.setAge(4); //发送sql sqlSession.insert("insertUser", user); //提交事务 sqlSession.commit(); // 释放资源 sqlSession.close();
映射文件须要dtd约束,在依赖包没有包含dtd的配置方法,只能从官方文档中获取,这里给一下。
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
基础结构,下面是一个大体的映射文件结构,在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="user"> <select id="getUserById" parameterType="int" resultType="work.pojo.User" > SELECT * FROM USER WHERE id = #{id} </select> </mapper>
命名空间.SQL ID
。select标签用来定义查询类的SQL语句。
命名空间.SQL ID
来调用对应的SQL语句。】示例:
<select id="getUserById" parameterType="int" resultType="user" > SELECT * FROM USER WHERE id = #{id1} </select>
#{参数名}
来向SQL语句传递参数。
<select id="getUserById" parameterType="int" resultType="work.pojo.User" > SELECT * FROM USER WHERE id = #{id1} </select>
对于对象类型,因为对象中有属性,因此要使用#{属性名}
来把对象中的数据传递给SQL。若是对象的属性仍是一个对象那么可使用#{内含对象名.属性名}
。
<!-- 因为传参是同样的用法,这里用insert做为例子,User中有属性name和age --> <insert id="insertUser" parameterType="work.pojo.User" > INSERT INTO USER(name,age) VALUES (#{name},#{age}); </insert>
%
这个东西在哪里存:
#{参数名}
来获取参数。
sqlSession.selectList("user.getUserByName","%唐%");
,SQL中使用#{参数名}
:SELECT * FROM USER WHERE name LIKE #{name};
${参数名}
能够用来字符串拼接,它能够在将字符串包裹的${参数名}
转成对应的数据,但对于非POJO类型的参数名只能为value,对于POJO类型的就只能使用POJO类型的属性了。
SELECT * FROM USER WHERE name LIKE '%${value}%';
SELECT * FROM USER WHERE name LIKE CONCAT('%',#{name},'%')
SELECT * FROM USER WHERE id = #{id}
的返回值应该是一个User类。假设数据表中的字符名为username,但对象中的属性名为name,那么怎么对应上呢?
<!-- SELECT id,username ,age FROM USER WHERE id = #{id} --><!--因为字符名与属性名不彻底相同,自动映射失败--> <!-- 使用下面的语句,利用别名 --> SELECT id,username as name ,age FROM USER WHERE id = #{id}
使用resultMap,显式对应:property是类对象的属性名,column是字段名
<resultMap type="work.pojo.User" id="userMap"> <id property="id" column="id" /> <!-- 手动把字段名与属性对应上 --> <result property="name" column="username" /> <result property="age" column="age"/> </resultMap>
resultMap用来显式定义数据封装规则,resultMap把数据表的数据与对象的属性一一对应起来,若是SQL语句的返回结果类型使用了resultMap,这样MyBatis就会根据resultMap中的规则来封装返回的数据。
result标签:用来定义普通字段的映射关系。
<!-- 定义resultMap --> <resultMap type="work.pojo.User" id="userMap"> <!--id标签把数据表中的id字段与User类中的id属性对应起来 --> <id property="id" column="id" /> <result property="name" column="name" /> <result property="age" column="age"/> </resultMap> <!-- 引用resultMap --> <select id="getUserById" parameterType="int" resultMap="userMap"> SELECT * FROM USER WHERE id = #{id1} </select>
resultMap还与关联查询有关系,关联查询依靠resultMap来定义映射关系。这留到后面讲。
insert用来定义插入语句
属性:
使用说明:增删改三种语句默认是不提交,要commit
<insert id="insertUser" parameterType="work.pojo.User" > INSERT INTO USER(name,age) VALUES (#{name},#{age}); </insert>
主键返回问题,有时候咱们但愿插入了一条记录后,获取到它的ID来处理其余业务,那么这时候咱们怎么获取它的主键呢?下面列举两种方法:
JDBC式:在insert标签上配置useGeneratedKeys和keyProperty属性,useGeneratedKeys用来代表这个数据库是否是自增加id的,因此这个获取主键的方式不适用与Oracle。keyProperty用来指明返回的主键值存储到哪一个属性中。
<insert id="save" parameterType="work.domain.User" useGeneratedKeys="true" keyProperty="userId" > insert into user(userName,password,comment) values(#{userName},#{password},#{comment}) </insert>
数据库式:利用数据库的函数来获取主键,keyProperty用来指明返回的主键值存储到哪一个属性中。order用来指定执行的顺序,到底是插入前获取--BEFORE,仍是插入后获取--AFTER。resultType用来指明返回主键的数据类型。
<insert id="save" parameterType="work.domain.User" > <selectKey resultType="java.lang.Long" order="AFTER" keyProperty="userId"> SELECT LAST_INSERT_ID() </selectKey> insert into user(userName,password) values(#{userName},#{password}) </insert>
属性与insert差很少
MyBatis因为是根据SQL去修改,因此它不会发生覆盖修改问题(Hibernate基于对象来查询,对于没有设置值的属性也会修改到数据表中,因此Hibernate中一般都是先查询后修改)
<update id="updateUser" parameterType="com.pojo.User"> UPDATE USER SET username = #{username} WHERE id = #{id} </update>
属性与insert差很少
<delete id="deleteUser" parameterType="int"> DELETE FROM user WHERE `id` = #{id1} </delete>
<sql id="userCols"> id,name,age </sql> <!-- 开始引用 --> <select id="getUserById" parameterType="int" resultType="work.pojo.User"> <!-- SELECT id,name,age FROM USER WHERE id = #{id1} --> SELECT <include refid="userCols"></include> FROM USER WHERE id = #{id1} </select>
上面学过了映射文件里面定义SQL,那么下面来了解一下怎么使用这些SQL语句。发送SQL的方式有两种,一种是使用SqlSession来发送,一种是使用Mapper来发送。
1.建立映射文件,这里假设为user.xml
<?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="user"> <select id="getUserById" parameterType="int" resultType="user" > SELECT id,name,age FROM USER WHERE id = #{id} </select> </mapper>
2.在配置文件中引入映射文件:【因为没有怎么讲mybatis配置文件,你能够先按照基础示例里面来修改】
<mappers> <!-- 导入映射文件 --> <mapper resource="work/pojo/user.xml"/> </mappers>
3.获取SqlSession,并使用SqlSession调用对应的SQL:
@Test public void test3() throws IOException { SqlSessionFactoryBuilder sfb=new SqlSessionFactoryBuilder(); InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sessionFactory = sfb.build(inputStream); SqlSession sqlSession = sessionFactory.openSession(); //根据SQL ID来发送SQL,第二个是传给SQL的参数。 User user = sqlSession.selectOne("user.getUserById",3); System.out.println(user); sqlSession.close(); }
1.首先建立一个接口,
package work.pojo; public interface UserMapper { public User getUserById(int id); }
2.建立映射文件(这里假设为UserMapper.xml),映射文件要求namespace必需是接口的全路径名:
<!-- namespace要写接口的全限定名 --> <mapper namespace="work.pojo.UserMapper"> <!--注意返回类型和入参类型要与接口的一致 --> <select id="getUserById" parameterType="int" resultType="work.pojo.User" > SELECT id,name,age FROM USER WHERE id = #{id} </select> </mapper>
3.在配置文件中引入Mapper:
<mappers> <!-- 导入映射文件 --> <!--既能够导入接口,也能够导入映射文件 --> <!--<mapper resource="work/pojo/UserMapper.xml"/> --> <mapper class="work.pojo.UserMapper"/> </mappers>
4.在代码中利用sqlSession获取接口的Mapper,并使用Mapper发送SQL(调用对应的接口方法就是发送对应SQL):【这里提一下,虽然获取的是接口,但因为遵循了开发规范,Mybatis会帮忙建立一个这个接口的实现类,因此实质返回的是一个实现类对象】
@Test public void test4() throws IOException { SqlSessionFactoryBuilder sfb=new SqlSessionFactoryBuilder(); InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sessionFactory = sfb.build(inputStream); SqlSession sqlSession = sessionFactory.openSession(); //根据接口.class来获取mapper UserMapper mapper = sqlSession.getMapper(UserMapper.class); //调用接口的方法就是调用方法对应的SQL。 User user = mapper.getUserById(3); System.out.println(user); sqlSession.close(); }
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
传入一个UserMapper.class就能够获取一个可以调用方法的mapper,咱们仅仅定义了UserMapper接口,为何能获取一个可以获取一个可以调用方法的mapper呢?由于mybatis底层自动帮咱们去建立这个接口的实现类了,因为咱们遵循了设计规范,mybatis可以很容易地了解该如何去建立实现类。建立完实现类后,返回一个实现类的对象。SqlSession方式:
Mapper方式:因为UserMapper接口已经包含原来的UserDao的功能了,而且不须要自定义实现类,因此这里能够省去DAO层。
两种方式比较:
mapper.getRole(1L)
。配置文件的dtd约束配置信息并无写在jar包中,因此咱们不能从依赖包中查到,只能依靠官方文档来获取,下载的包中的mybatis-3.4.5.pdf中就有,在 Getting started中能够复制dtd约束。
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
标签的出现的顺序必须按照顺序。
<configuration><!-- configuration是配置文件的顶级标签 --> <!-- properties用于配置一些参数,这些参数能够被引用到下面的其余配置中,至关于properties文件 --> <properties></properties> <!-- setting用于配置一些mybatis底层相关的属性,好比缓存 --> <settings></settings> <!--typeAliases 用于配置类型命名 --> <typeAliases></typeAliases> <!-- typeHandlers用于配置类型处理器 --> <typeHandlers></typeHandlers> <!-- objectFactory用于配置对象工厂 --> <objectFactory type=""></objectFactory> <!--plugins用于配置插件 --> <plugins></plugins> <!-- environments配置不一样的数据库链接环境 --> <environments default=""> <environment id=""> <!--environment用于配置数据库链接环境 --> <!-- transactionManager用于配置事务管理器 --> <transactionManager type=""></transactionManager> <!--dataSource用于配置数据源 --> <dataSource type=""></dataSource> </environment> </environments> <!-- databaseIdProvider是数据库产商标识 --> <databaseIdProvider type=""></databaseIdProvider> <!-- mappers用于配置映射器 --> <mappers></mappers> </configuration>
上面的标签中,plugins涉及插件,是偏向底层的内容,若是不了解mybatis运行原理,那么可能会比较晦涩,这会留到另一篇博文再讲述(若是有空的话)。【databaseIdProvider和objectFactory不讲述】
下面主要讲properties、settings、typeAliases、typerHandler、environments、mappers。
environments用来配置多个数据库链接环境,每个环境都使用environment标签来定义。(不一样的环境能够定义不一样的数据库链接信息)
<environments default="development">省略environment配置</environments>
表明默认使用id="development"的环境。sqlSession.comit()
来进行事务提交。<transactionManager type="JDBC" ></transactionManager>
<environments default="development"> <!-- environment用来定义数据库环境,environments用来定义多个environment --> <environment id="development"> <!-- 配置事务管理,使用jdbc事务管理 --> <transactionManager type="JDBC" /> <!-- 配置数据库链接池 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/mybatis2" /> <property name="username" value="root" /> <property name="password" value="123456" /> </dataSource> </environment> </environments>
properties标签的做用相似properties文件,properties标签能够导入properties配置文件,也能够直接使用子标签property来配置参数。properties标签中配置的参数能够在后面的其它属性配置中引用。
使用方式:
用properties标签导入配置文件:
<!-- 示例 --> <properties resource="jdbc.properties"></properties>导入后,根据
${键名}
来引用配置文件中配置的参数,例如在配置数据源的时候:<property name="driver" value="${jdbc.driverClass}" />
用properties标签订义property变量,定义后也可使用${键名}
来引用。
设置参数:
<properties> <property name="db.driver" value="com.mysql.jdbc.Driver"/> <property name="db.url" value="jdbc:mysql://localhost:3306/mybatis2"/> <property name="db.user" value="root"/> <property name="db.password" value="123456"/> </properties>
引用参数:
<environment id="test"> <!-- 配置事务管理,使用jdbc事务管理 --> <transactionManager type="JDBC" /> <!-- 配置数据库链接池 --> <dataSource type="POOLED"> <property name="driver" value="${db.driver}" /> <property name="url" value="${db.url}" /> <property name="username" value="${db.user}" /> <property name="password" value="${db.password}" /> </dataSource> </environment>
为了分清楚配置的属性的做用,一般都会使用点分法来定义变量,如可使用db.xxx表明这个配置与数据库相关。【固然,不使用点分法也能够】
https://blog.csdn.net/u014231523/article/details/53056032
,好像写的算靠谱了。typeAliases一般用来别名,定义别名后,能够把很长的名字定义成一个较短的名字,例如类的全限定名(qualified name)很长时,能够用一个别名来表明这个类路径。
别名可使用在映射文件中,一般能够把类的全限定名定义成别名,这样就能够简写了。
别名分为系统定义别名和自定义别名
系统定义别名主要是一些数据类型别名,因此要注意定义sql的入参类型和结果类型,SQL语句的结果类型resultType定义成int的时候,返回的结果应该用Integer类型的变量存储
别名 | 映射的类型 |
---|---|
_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 |
自定义别名:
可使用typeAlias标签来定义别名:
<typeAliases> <!-- alias的值是别名,type的值是要定义别名的名字 --> <typeAlias type="work.pojo.User" alias="user"/> </typeAliases>
别名包扫描:
<typeAliases> <!-- 整个包下的类都被定义别名,别名为类名,不区分大小写--> <package name="work.pojo"/> <!--这样pojo下的类都被定义成了别名,例如work.pojo.User能够简写成user --> </typeAliases>
别名是忽略大小写的,因此别名user,你既可使用user来引用,也可使用User来引用。
typeHandler是用来处理类型转换问题的,从数据库中获取的数据要想装入到对象中,势必要通过类型转换,比如MyBatis必须知道如何将varchar转成String。对于常见的类型转换,MyBatis已经帮咱们定义了很多类型转换器,下面给出常见的。
数据库数据类型 | Java类型 | 类型转换器 |
---|---|---|
CHAR, VARCHAR |
String | StringTypeHandler |
BOOLEAN | Boolean | BooleanTypeHandler |
SMALLINT |
Short |
ShortTypeHandler |
INTEGER |
Integer |
IntegerTypeHandler |
FLOAT |
Float |
FloatTypeHandler |
DOUBLE |
Double |
DoubleTypeHandler |
因为MyBatis的转换器已经可以解决大部分问题了,因此这里不讲怎么自定义转换器,有兴趣的能够自查。
mappers是用来引入映射器(映射文件)的,有了映射器,Mybatis才可以管理到在映射文件中定义的SQL。
引入方式:
导入配置文件,经过配置文件的路径名导入:
<mappers> <!-- 第一种方式,根据映射文件路径--> <mapper resource="work/pojo/user.xml"/> </mappers>
使用mapper方式开发时,因为映射文件与mapper对应,也能够经过mapper的全限定名导入:
【要求映射文件与mapper处于同一目录,并且映射文件的文件名与要mapper名一致】
<mappers> <!-- 对下面的配置,要求映射配置文件的文件名为UserMapper.xml;要求UserMapper.xml与UserMapper处于同一目录下--> <mapper class="work.mapper.UserMapper"/> </mappers>
使用mapper方式开发时,因为映射文件与mapper对应,也能够经过扫描mapper所在的包来导入:
【要求映射文件与mapper处于同一目录,并且映射文件的文件名与要mapper名一致】
<mappers> <!-- 第三种方式,包扫描器: 一、映射文件与接口同一目录下 二、映射文件名必需与接口文件名称一致 --> <package name="work.mapper"/> </mappers>
下面的SQL语句,若是调用的时候不传参,将获得SELECT * FROM USER WHERE age = null;
<select id="getUserByAge" parameterType="int" resultType="work.pojo.User"> SELECT * FROM USER WHERE age = #{age}; </select>
利用if标签解决问题:
<select id="getUserByAge" parameterType="int" resultType="work.pojo.User"> SELECT * FROM USER <if test="age!=null "> WHERE age = #{age} </if> </select>
where主要用于处理多个判断条件的拼接。在where A条件 and B条件可能须要判断一下A和B的合法性,若是仅仅使用if标签那么可能会致使where、and字符串重复,而where会自动处理多余的and和where,还会自动加上where。
<select id="getUserByAgeOrName" parameterType="work.pojo.User" resultType="work.pojo.User"> SELECT * FROM USER <where> <if test="age!=null "> and age = #{age} </if> <if test="name!=null"> and name like '%${name}%' </if> </where> </select>
where标签能够解决查询条件中的where问题,但若是对一个对象进行update时,如何判断传入的set值是否为空呢?可使用if来进行判断,而后再使用set标签解决条件字符串重复问题,set标签能够去除多余的逗号。
<update id="updateUser" parameterType="work.pojo.User"> UPDATE USER SET name=#{name}, age=#{age} where id=#{id} </update>
<update id="updateUser" parameterType="work.pojo.User"> UPDATE USER <set> <if test="name!=null">name=#{name},</if> <if test="age!=null">age=#{age}</if> </set> where id=#{id} </update>
<select id="getUserByAgeCollection" parameterType="List" resultType="work.pojo.User"> SELECT * FROM USER WHERE <foreach item="age" collection="list" open="age IN(" separator="," close=")"> #{age} </foreach> </select>
以一个部门对应一个经理为例。
建立一个POJO类,用链接查询语句查询出两个表的数据,经过resultType封装到一个POJO类中。
步骤:
1.首先建立一个POJO类,要求包含了部门信息和经理信息(若是你不想重复定义属性,也能够选择继承单个类的信息继承两个类,这里考虑到有选择地查询字段因此不继承):
package work.pojo; public class Department_Manager { //部门的信息 private Integer did; private String department_name; //经理的信息 private Integer mid; private String name; private Double salary; public Integer getDid() { return did; } public void setDid(Integer did) { this.did = did; } public String getDepartment_name() { return department_name; } public void setDepartment_name(String department_name) { this.department_name = department_name; } public Integer getMid() { return mid; } public void setMid(Integer mid) { this.mid = mid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getSalary() { return salary; } public void setSalary(Double salary) { this.salary = salary; } @Override public String toString() { return "Department_Manager [did=" + did + ", 部门名=" + department_name + ", mid=" + mid + ", 经理名="+ name + ", 工资=" + salary + "]"; } }
数据表的建立(要注意,因为存在关系,那么两个表之间确定有一个字段用于创建关联,在POJO类中能够没有这个字段,但表中必定要有,由于SQL语句依靠这个来查询):
use mybatis2; create table department( did int primary key auto_increment, department_name varchar(20) ); create table manager( mid int primary key auto_increment, name varchar(20), salary double(7,2), did int, foreign key(did) references department(did) --这里用外键关联 ); insert into department values(null,'开发部'),(null,'市场部'); insert into manager values(null,'张三',20000.00,1),(null,'李四',20000.00,2);
2.编写SQL语句:【这里使用Mapper方式】
定义接口:
package work.pojo; public interface UserMapper { public Department_Manager[] getDepartmentManager(); }
建立映射文件:
<?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="work.pojo.UserMapper"> <select id="getDepartmentManager" resultType="work.pojo.Department_Manager" > SELECT d.did,d.department_name, m.mid,m.name,m.salary FROM department d LEFT JOIN manager m ON d.did = m.did </select> </mapper>
3.编写测试方法:
@Test public void test5() throws IOException { SqlSessionFactoryBuilder sfb=new SqlSessionFactoryBuilder(); InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sessionFactory = sfb.build(inputStream); SqlSession sqlSession = sessionFactory.openSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Department_Manager[] departmentManager = mapper.getDepartmentManager(); for (Department_Manager department_Manager : departmentManager) { System.out.println(department_Manager); } sqlSession.close(); }
因此第一种方式是把数据封装到一个包含了多个表的全部字段的POJO对象的方式。若是有多个表,有多种关系的话,第一种方式会显得麻烦复杂。
建立一个在部门类里面添加一个经理类对象,用链接查询语句查询出两个表的数据,经过resultMap把查出来的数据封装到部门类中。
步骤:
1.建立经理类,建立部门类,在部门类中添加一个经理类对象。
经理类:
java package work.pojo; public class Manager { private Integer mid; private String name; private Double salary; private Integer did; //did是部门表的主键,你能够不定义,由于关注点在部门,你也能够定义成一个部门对象。 public Integer getMid() { return mid; } public void setMid(Integer mid) { this.mid = mid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getSalary() { return salary; } public void setSalary(Double salary) { this.salary = salary; } public Integer getDid() { return did; } public void setDid(Integer did) { this.did = did; } @Override public String toString() { //因为没有给did封装数据,因此这里不打印did return "Manager [mid=" + mid + ", name=" + name + ", salary=" + salary + "]"; } }
部门类:
package work.pojo; public class Department { private Integer did; private String department_name; //经理的映像 private Manager manager; public Integer getDid() { return did; } public void setDid(Integer did) { this.did = did; } public String getDepartment_name() { return department_name; } public void setDepartment_name(String department_name) { this.department_name = department_name; } public Manager getManager() { return manager; } public void setManager(Manager manager) { this.manager = manager; } @Override public String toString() { return "Department [did=" + did + ", department_name=" + department_name + ", manager=" + manager + "]"; } }
2.定义映射文件和接口:
定义接口:
package work.pojo; public interface UserMapper { public Department_Manager[] getDepartmentManager2(); }
建立映射文件,使用resultMap定义多表关联映射规则:
<?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="work.pojo.UserMapper"> <resultMap type="work.pojo.Department" id="department_manager"> <id property="did" column="did" /> <result property="department_name" column="department_name" /> <!--association用来处理对象中存在另外一个类的对象的状况, property是对象中另外一个类的对象变量名,javaType是另外一个类的全限定名 标签里面使用id和result来映射数据与另外一个类的对象的关系。 --> <association property="manager" javaType="work.pojo.Manager"> <id property="mid" column="mid"/> <result property="name" column="name" /> <result property="salary" column="salary"/> <!-- 这里要注意不要封装外键字段,由于咱们这里的经理表的外键是did,部门表主键是did,会命名冲突;因为这里没封装数据给经理类的did,因此经理类的did是没有数据的;若是你想给经理类的did赋值,那么你应该利用别名,在SQL中令m.did m_did,而后上面使用<result property="did" column="m_did"/> --> </association> </resultMap> <select id="getDepartmentManager2" resultMap="department_manager" > SELECT d.did,d.department_name, m.mid,m.name,m.salary FROM department d LEFT JOIN manager m ON d.did = m.did </select> </mapper>
3.编写测试方法:
@Test public void test6() throws IOException { SqlSessionFactoryBuilder sfb=new SqlSessionFactoryBuilder(); InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sessionFactory = sfb.build(inputStream); SqlSession sqlSession = sessionFactory.openSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Department[] departments = mapper.getDepartmentManager2(); for (Department department : departments) { System.out.println(department); } sqlSession.close(); }
若是采用相似上面一对一的方式一来处理一对多话,一一方的会出现不少次(方式一是封装查询的每行记录,一对多查询的时候一一方的数据会出现屡次,因此采用方式二来实现一对多)。下面以一个班级能够有多个学生为例。
步骤:
1.建立Student类,建立Grade类,在Grade中添加一个由Student对象组成的List:
Student类:
package work.pojo; public class Student { private Integer sid; private String stu_name; public Integer getSid() { return sid; } public void setSid(Integer sid) { this.sid = sid; } public String getStu_name() { return stu_name; } public void setStu_name(String stu_name) { this.stu_name = stu_name; } @Override public String toString() { return "Student [sid=" + sid + ", stu_name=" + stu_name + "]"; } }
Grade类:
package work.pojo; import java.util.List; public class Grade { private Integer gid; private String grade_name; private List<Student> students; public Integer getGid() { return gid; } public void setGid(Integer gid) { this.gid = gid; } public String getGrade_name() { return grade_name; } public void setGrade_name(String grade_name) { this.grade_name = grade_name; } public List<Student> getStudents() { return students; } public void setStudents(List<Student> students) { this.students = students; } @Override public String toString() { return "Grade [gid=" + gid + ", grade_name=" + grade_name + ", students=" + students + "]"; } }
2.建立数据表,插入测试数据:
create table grade( gid int primary key auto_increment, grade_name varchar(20) ); create table student( sid int primary key auto_increment, stu_name varchar(20), gid int, foreign key(gid) references grade(gid) ); insert into grade values(null,"python班"),(null,'Java班'); insert into student values(null,'张三',1),(null,'李四',1),(null,'王五',2),(null,'赵六',2);
3.建立mapper接口和映射文件:
接口:
package work.pojo; public interface UserMapper { public Grade[] getGradeStudent(); }
映射文件:
<?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="work.pojo.UserMapper"> <resultMap type="work.pojo.Grade" id="grade_student_map"> <id property="gid" column="gid"/> <result property="grade_name" column="grade_name"/> <!-- collection用来处理一个类中含有其余类的集合时的数据映射(一对多) property是集合的变量名,ofType是集合元素的全限定名, collection内使用id和result创建映射关系 --> <collection property="students" ofType="work.pojo.Student" > <id property="sid" column="sid"/> <result property="stu_name" column="stu_name" /> </collection> </resultMap> <select id="getGradeStudent" resultMap="grade_student_map"> SELECT g.gid,g.grade_name, s.sid,s.stu_name FROM grade g LEFT JOIN student s ON g.gid = s.gid </select> </mapper>
4.编写测试方法:
@Test public void test7() throws IOException { SqlSessionFactoryBuilder sfb=new SqlSessionFactoryBuilder(); InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sessionFactory = sfb.build(inputStream); SqlSession sqlSession = sessionFactory.openSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Grade[] gradeStudent = mapper.getGradeStudent(); for (Grade grade : gradeStudent) { System.out.println(grade); } sqlSession.close(); }
因为多对多太过复杂,Mybatis不支持多对多,Mybatis选择使用两个一对多来实现多对多。下面以一名学生能够选多门课,一门课能够被多个学生选为例。【多对多关系模型是两方都有对方的数据,两方都能查询到对方的数据,因此咱们使用一对多的时候,能向两方的对象中都装入数据,就能够达到多对多的效果;但有一点效果不能达到,(以例子讲解)课程对象中的学生集合没有与课程对象创建上关系,但从业务需求来讲一般不关注另一方的关系(若是关注,从学生一方查询便可,为何要使用课程中的学生对象?),因此这个缺点也不算缺点。另外,下面也会讲一下解决这个问题的方法。】
步骤:
1.建立Cource类,建立SchoolChild类,分别在两个类中建立对方类的集合:【这里要注意toString问题,若是A的toString包含B,B包含A,那么会死循环。】
Cource类:
package work.pojo; import java.util.List; public class Cource { private Integer cid; private String cource_name; private List<SchoolChild> schoolchilds; public Integer getCid() { return cid; } public void setCid(Integer cid) { this.cid = cid; } public String getCource_name() { return cource_name; } public void setCource_name(String cource_name) { this.cource_name = cource_name; } public List<SchoolChild> getSchoolchilds() { return schoolchilds; } public void setSchoolchilds(List<SchoolChild> schoolchilds) { this.schoolchilds = schoolchilds; } }
SchoolChild类:
package work.pojo; import java.util.List; public class SchoolChild { private Integer sid; private String stu_name; private List<Cource> cources; public Integer getSid() { return sid; } public void setSid(Integer sid) { this.sid = sid; } public String getStu_name() { return stu_name; } public void setStu_name(String stu_name) { this.stu_name = stu_name; } public List<Cource> getCources() { return cources; } public void setCources(List<Cource> cources) { this.cources = cources; } }
2.建立表(注意有中间表):
create table cource( cid int primary key auto_increment, cource_name varchar(20) ); create table schoolChild( sid int primary key auto_increment, stu_name varchar(20) ); create table cource_schoolChild( cid int, sid int, foreign key(cid) references cource(cid), foreign key(sid) references schoolChild(sid) ); insert into cource values(null,"python"),(null,'Java'); insert into schoolChild values(null,'张三'),(null,'李四'),(null,'王五'); insert into cource_schoolChild values(1,1),(1,2),(1,3),(2,1),(2,3);
3.建立接口和映射文件:
接口:
package work.pojo; public interface UserMapper { public Cource[] getCource(); public SchoolChild[] getSchoolChild(); }
映射文件:【难点是sql语句,其余的resultMap与一对多的同样】
<?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="work.pojo.UserMapper"> <resultMap type="work.pojo.Cource" id="cource_schoolchild_map"> <id property="cid" column="cid" /> <result property="cource_name" column="cource_name" /> <collection property="schoolchilds" ofType="work.pojo.SchoolChild"> <id property="sid" column="sid" /> <result property="stu_name" column="stu_name" /> </collection> </resultMap> <select id="getCource" resultMap="cource_schoolchild_map"> select t1.cid,t1.cource_name, t3.sid,t3.stu_name from cource t1 left join cource_schoolChild t2 on t1.cid=t2.cid left join schoolChild t3 on t2.sid=t3.sid; </select> <resultMap type="work.pojo.SchoolChild" id="schoolchild_cource_map"> <id property="sid" column="sid" /> <result property="stu_name" column="stu_name" /> <collection property="cources" ofType="work.pojo.Cource"> <id property="cid" column="cid" /> <result property="cource_name" column="cource_name" /> </collection> </resultMap> <select id="getSchoolChild" resultMap="schoolchild_cource_map"> select t1.cid,t1.cource_name, t3.sid,t3.stu_name from cource t1 left join cource_schoolChild t2 on t1.cid=t2.cid left join schoolChild t3 on t2.sid=t3.sid; </select> </mapper>
4.编写测试方法:
@Test public void test8() throws IOException { SqlSessionFactoryBuilder sfb=new SqlSessionFactoryBuilder(); InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sessionFactory = sfb.build(inputStream); SqlSession sqlSession = sessionFactory.openSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Cource[] cources = mapper.getCource(); for (Cource cource : cources) { System.out.println(cource); } System.out.println("---分隔线---"); SchoolChild[] schoolChilds = mapper.getSchoolChild(); for (SchoolChild schoolChild : schoolChilds) { System.out.println(schoolChild); }
5.测试结果:
Cource [cid=1, cource_name=python, schoolchilds=[SchoolChild [sid=1, stu_name=张三, cources=null], SchoolChild [sid=2, stu_name=李四, cources=null], SchoolChild [sid=3, stu_name=王五, cources=null]]] Cource [cid=2, cource_name=Java, schoolchilds=[SchoolChild [sid=1, stu_name=张三, cources=null], SchoolChild [sid=3, stu_name=王五, cources=null]]] ---分隔线--- SchoolChild [sid=1, stu_name=张三, cources=[Cource [cid=1, cource_name=python, schoolchilds=null], Cource [cid=2, cource_name=Java, schoolchilds=null]]] SchoolChild [sid=2, stu_name=李四, cources=[Cource [cid=1, cource_name=python, schoolchilds=null]]] SchoolChild [sid=3, stu_name=王五, cources=[Cource [cid=1, cource_name=python, schoolchilds=null], Cource [cid=2, cource_name=Java, schoolchilds=null]]]
在上面的测试结果中,课程对象中查出的学生对象的课程对象是null,这是由于没有封装上,下面能够提供一种方法来解决上面这个问题,但要注意--这个问题是解决不了的:这是由于MyBatis是面向SQL的,你定义了映射规则它才能帮你封装,MyBatis对于对象与对象中嵌套对象的关系并不了解,它不知道怎么作,只有你进行了封装定义才可以给嵌套对象封装数据。若是你在resultMap的collection中嵌套一个collection就能够对嵌套对象中的嵌套对象封装数据,但嵌套对象中的嵌套对象的嵌套对象里的对象仍是会空的。
<?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="work.pojo.UserMapper"> <resultMap type="work.pojo.Cource" id="cource_schoolchild_map"> <id property="cid" column="cid" /> <result property="cource_name" column="cource_name" /> <collection property="schoolchilds" ofType="work.pojo.SchoolChild"> <id property="sid" column="sid" /> <result property="stu_name" column="stu_name" /> <!-- 给嵌套对象里面的嵌套对象封装数据 --> <collection property="cources" ofType="work.pojo.Cource"> <id property="cid" column="cid" /> <result property="cource_name" column="cource_name" /> </collection> </collection> </resultMap> <select id="getCource" resultMap="cource_schoolchild_map"> select t1.cid,t1.cource_name, t3.sid,t3.stu_name from cource t1 left join cource_schoolChild t2 on t1.cid=t2.cid left join schoolChild t3 on t2.sid=t3.sid; </select> <!-- 省略SchoolChild的。 --> </mapper>
<mapper namespace="work.mapper.ProductMapper"> <resultMap type="work.domain.Product" id="product_category"> <id property="pid" column="pid"/> <result property="pname" column="pname"/> <result property="price" column="price"/> <result property="pimage" column="pimage"/> <result property="pdesc" column="pdesc"/> <!-- 这里是多表查询操做,这里商品里面有一个商品分类外键 --> <association property="category" javaType="work.domain.Category"> <result property="category_name" column="category_name"/> </association> </resultMap> <select id="findAll" resultMap="product_category"> select p.pid,p.pname,p.price,p.pimage,p.pdesc, c.cid,c.category_name from product p left join category c on p.cid = c.cid; </select> <insert id="save" parameterType="work.domain.Product"> insert into product(pname,price,pimage,pdesc,cid) values( #{pname},#{price},#{pimage},#{pdesc},#{category.cid} ); </insert> </mapper>
@Test public void test9() throws IOException { SqlSessionFactoryBuilder sfb=new SqlSessionFactoryBuilder(); InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sessionFactory = sfb.build(inputStream); SqlSession sqlSession = sessionFactory.openSession(); //根据接口.class来获取mapper UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.getUserById(3); User user2 = mapper.getUserById(3); System.out.println(user); System.out.println(user==user2); sqlSession.close(); }
在select\delete\insert标签 中,有一个flushCache属性:设置查询以后是否删除本地缓存和二级缓存。
整合第三方链接池,固然要引入依赖包啦。这里就很少讲了,就是第三方链接池的依赖包。
首先须要定义一个数据源工厂,这个工厂要继承UnpooledDataSourceFactory,在构造函数中返回须要使用的链接池对象
package work.dataSource; import org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory; import com.mchange.v2.c3p0.ComboPooledDataSource; public class C3P0DataSourceFactory extends UnpooledDataSourceFactory { public C3P0DataSourceFactory(){ this.dataSource=new ComboPooledDataSource(); } }
而后在mybatis-config.xml中配置使用第三方链接池:
<!-- type里填刚才定义的链接池工厂的全限定名 --> <dataSource type="work.dataSource.C3P0DataSourceFactory"> <!-- 下面的属性名要按照链接池自身的规则来配置,好比c3p0的驱动参数是driverClass --> <property name="driverClass" value="com.mysql.jdbc.Driver" /> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mybatis2" /> <property name="user" value="root" /> <property name="password" value="123456" /> <property name="idleConnectionTestPeriod" value="60" /> <property name="maxPoolSize" value="20" /> <property name="maxIdleTime" value="600" /> </dataSource>
如今没有写的内容:
不写,有兴趣自查的内容: