要使用mybatis,需要在类路径下建立一个配置文件,名称为mybatis-config.xml
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在集成Spring后不用配置,environment 元素体中包含了事务管理和连接池的配置 -->
<!--environments 的id可以随意配置-->
<environments default="development">
<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/ssm_mybatis" />
<property name="username" value="root" />
<property name="password" value="123456789" />
</dataSource>
</environment>
</environments>
<!--用来关联实体类,xml对应一个类-->
<mappers>
<mapper resource="mapper/UserMapper.xml" />
</mappers>
</configuration>
mybatis中的Mapper.xml:
mybatis通过实体类访问数据库,实体类要符合JavaBean规范
实体类要对应一个mapper.xml,名称随意,最好是类名 + Mapper.xml
如下(UserMapper.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:便于管理,相当于给mapper起个名字
在mapper内部是写sql语句的
-->
<mapper namespace="UserMapper">
<!--select属性:
id:给sql语句命名,用来调用
parameterType:传入参数的类型(可选)
resultType:返回值的类型(类路径),即使有多个返回值,不用写list类
-->
<select id="selectUserById" parameterType="Integer" resultType="model.User">
<!--sql语句和原生的几乎一样,占位符不再是?,而是#{},而且需要取名字,名字没有要求-->
select * from user where u_id = #{id}
</select>
</mapper>
mybatisAPI以及基本查询:
在类中使用mybatisAPI使用mybatis操作数据库:
//将mybatis的配置文件路径保存为String,在类路径下可以直接保存名称
String resource = "mybatis-config.xml";
//使用mybatis提供Resources读取配置文件,获取一个输入流
InputStream inputStream = Resources.getResourceAsStream(resource);
//新建一个mybatis提供的sqlSessionFactoryBuilder
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//利用创建的builder读取输入流的数据创建SessionFactory
SqlSessionFactory factory = builder.build(inputStream);
//利用工厂打开一个sqlSession
SqlSession session = factory.openSession();
//操作数据库
// 参数1:要操作的SQL语句名称,在实体类的mapper文件里配置名称,命名空间 + id
// 参数2:sql语句的传入参数
// 查询一条数据,通过id = 1
User user = (User)session.selectOne("UserMapper.selectUserById", 1);
// 如果进行增删改操作,则需要提交事务
// session.commit();
mybatis其他数据库操作方式:
模糊查询:
///xml配置
//模糊查询不能使用#{},需要使用${},名称必须为value,${}为ognl表达式,可以用来字符串拼接
//如有需要,注意查询前设置数据库编码为utf8,否则无法显示中文数据
<select id="selectUserByName" parameterType="String" resultType="model.User">
select * from user where u_id like '%${value}%'
</select>
//java语句
//如果查询结果为多个,可以用selectList
List<User> list = session.selectList("UserMapper.selectUserByName", "王");
插入数据:
//xml配置
<insert id="insertUser" parameterType="model.User">
//使用#{}可以获取user实例中的字段,用法类似ognl表达式
insert into user values(null, #{u_username},#{u_password},#{u_sex},#{u_createTime},#{u_cid});
</insert>
//java代码
User user = new User("A","B","C",new Date(),1);//创建测试实例
session.insert("insertUser", user);
session.commit();
修改数据
//xml配置
<update id="updateUserName" parameterType="model.User">
update user set u_username = #{u_username} where u_id = #{u_id};
</update>
//java代码
User user = new User();
user.setU_id(1);//mybatis根据数据的id修改数据
session.update("updateUserName", user);
session.commit();
删除数据
//xml配置
<delete id="deleteUser" parameterType="Integer">
delete from user where u_id = #{id};
</delete>
//java代码
session.delete("deleteUser", 1);
session.commit();
创建MybatisUtils(获取session):
package utils;
import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MybatisUtils {
private static SqlSessionFactory sessionFactory = null;
private static InputStream inputStream = null;
static {
String resource = "mybatis-config.xml";
try {
inputStream = Resources.getResourceAsStream(resource);
} catch (IOException e) {
e.printStackTrace();
}
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
sessionFactory = builder.build(inputStream);
}
public static SqlSession getSession(){
return sessionFactory.openSession();
}
}
mybatis动态代理(官方推荐):
使用一个可以和mapper.xml文件映射的接口实现动态代理
通过接口可mapper实现Dao的功能,而不是自己写Dao的实现类
UserMapper.xml
<mapper namespace="dao.UserMapper">
<select id="selectUserById" parameterType="Integer"
resultType="model.User">
select * from user where u_id = #{id};
</select>
</mapper>
UserMapper.java
public interface UserMapper {
//mapper动态代理开发四大原则
//1.接口方法名需要与mapper.xml的要调用的sql语句的id一致
//2.接口的形参类型需要与mapper.xml parameterType一致
//3.接口的返回值需要与mapper.xml resultType一致
//4.mapper.xml中namespace要与接口的全包名一致
public User selectUserById(Integer id);
}
动态方法调用:
//先使用getMapper获取接口实例(接口实例由mybatis根据mapper帮助实现)
UserMapper mapper = session.getMapper(UserMapper.class);
//然后就可以直接调用方法
User user = mapper.selectUserById(1);
在mybatis中使用log输出日志:
在项目目录下添加log4j.properties文件:
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# 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
%{}和#{}的区别:
#{}是占位符,运行时替换为‘参数’,带有单引号
%{}时ognl表达式,可以用作字符串拼接,传入参数不会添加单引号
mybatis中的properties属性:
properties(读取配置文件)
mybatis可以读取properties文件中的数据:
<properties resource="db.properties"/>
然后可以使用${}读取properties文件内容
通过方法参数传递的属性具有最高优先级,resource/url 属性中指定的配置文件次之,最低优先级的则是 properties 元素中指定的属性。
mybatis中的typeAliases(类型别名):
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。
推荐使用包的形式设置别名,如果Javabean的数量比较多的话,使用包的形式设置别名,包下的所有类使用只要使用类名即可
报的形式会扫描主包及自包下的所有文件,以对象类名为别名,大小写不限,推荐使用小写
<typeAliases>
<package name="model" />
</typeAliases>
mybatis中的mappers(配置映射器的位置):
mappers时写sql语句的地方
mappers可以使用绝对路径(url),相对路径(resource)、类名(class)、映射器
(name)定位,但由于都是单个配置,如果类多起来,比较麻烦,所以推荐使用包来配置:
<mappers>
<package name="mapper"/>
</mappers>
使用包配置时,主要要将接口(动态调用)和xml文件都放在此包下
mybatis中的输入输出映射:
mybatis中的输入映射:
parameterType:可以是基本数据类,包装类(不仅仅时Integer、Double,还可以时List< User >,或者是自定义的包装类),自定义类,
mybaits中的输出映射:
可以这样理解:
mybatis从数据库中查找数据,查出的数据是一张表,第一行是各个属性名称,以下每一行都是一条记录,每条记录都可以转化为一个对象,那么如何转化为对象?设置resultType提供一个类名,让mybatis自己判断如何构造对象:
resultType:
首先根据提供的类构造一个对象,然后再逐一扫描result表每一行记录,每条记录从左到右扫描,如果如果扫描位置有值,如果bean类中有对应名称的setter方法,则用setter方法设置到对象中,否则跳过。
resultMap: 如果指定的是resultMap,则在每个记录注意扫描时去resultMap中检查是否存在该名称的映射,如果有,则按照设置的映射关系映射,如果没有则按照resultType的规则映射。
resultType和resultMap不能共用,只能用其中的一个
什么时候使用哪个?
resultType(自动映射,如果是实体类,需要实体类中的属性和数据库中的表完全一致才可以使用):可以是基本类型、自定义对象或是集合
resultMap(手动映射,实体类中的属性可以不和数据库中的列完全一致命名):bean中的属性值和数据库中的列不匹配
手动映射(例子):
<!---->
<!--resultMap属性:
type:类型,就是映射bean类
id:由于resultMap单独设置在查询标签外,所以需要用id来找到该resultMap标签
result:可以理解为键值对映射
-property:bean类中和数据库列名不一致的但对应的那个属性
-column:数据库中和bean属性不一致但是对应的那一类
-->
<resultMap type="Country" id="country">
<result property="id" column="c_id"/>
</resultMap>
<!--然后使用select标签时设置resultMap属性为上述id,就可以了-->
<select id="selectAll" resultMap="country">
select * from country;
</select>
<!--没有设置的属性则会自动映射(需要属性名和数据库列名一致)-->
mybatis的关联查询:
在mybatis中设置关联的作用(个人理解):
其实使用sql进行多表查询已经不是问题,使用各种连接,只要有数据,都不是问题。问题是如何把这些数据封装成一个个对象方便操作呢?我们需要一个能够能承载查询信息的类,毫无疑问就是实体类,怎样把数据放到实体类中?这里需要使用resultMap(mybatis多表查询不能用resultType)
假如有一个用户类和一个国家类,则一个用户对一个国家,一个国家对多个用户。
示例:
一个用户对一个国家(一对一):
<!---->
<resultMap type="User" id="userinfo">
<!--使用多表查询时,只有手动配置的属性才会被查询,没有手动配置的属性不会获取-->
<!--使用id标识主键,使用result标识普通属性,可以混用,但是最好区别开-->
<id property="u_id" column="u_id" />
<result property="u_username" column="u_username" />
<result property="u_sex" column="u_sex" />
<result property="u_cid" column="u_cid" />
<!--association用来接收一对一的另一个表的信息(国安):
property:接受类中另一个类的引用名称
javaType:另一个类的类型
-->
<association property="country" javaType="Country">
<result property="c_countryname" column="c_countryname"/>
<result property="c_capital" column="c_capital"/>
</association>
</resultMap>
<select id="selectUserInfoOnetoOne"
resultMap="userinfo">
select
u_id,u_username,u_sex,u_cid,c_countryname,c_capital
from user u
left join
country c
on
u.`u_id` = c.`c_id`;
</select>
(一个国家对多个用户)一对多:
<!---->
<resultMap type="Country" id="countryuser">
<id property="c_id" column="c_id" />
<id property="c_countryname" column="c_countryname" />
<id property="c_capital" column="c_capital" />
<!--collection 属性:
property:接受类中的另一个类的集合引用
ofType:集合类范型类型
-->
<collection property="userLists" ofType="User">
<result property="u_username" column="u_username"/>
<result property="u_sex" column="u_sex"/>
</collection>
</resultMap>
<select id="selectCountryUserManytoOne" resultMap="countryuser">
select
c_id,c_countryname,c_capital,u_username,u_sex
from
country c
left join
user u
on
u.`u_cid` = c.`c_id`;
</select>
mybatis动态sql:方便拼接sql语句
if标签:
在mybatis的sql语句中,可以使用if标签根据参数是否存在执行不同的sql语句:
<!---->
<select id="selectUserUseIf" resultType="User" parameterType="User">
select u_id,
<!--test后面跟上条件,获取传入的值不需要加上#{}-->
<if test="u_username!=null">
u_username,
</if>
u_sex from user;
</select>
但是拼接的sql语句中有and关键字时容易出现问题:
<!---->
<!--如果u_sex== null,sql语句and就会直接连接在where后面,着显然是错的-->
<select id="selectUserUseIf" resultType="User" parameterType="User">
select * from user where
<if test="u_sex!=null and u_sex!=''">
u_sex = #{u_sex}
</if>
<if test="u_cid!=null">
and u_cid = #{u_cid}
</if>
</select>
mybatis提供了where标签解决这个问题,如果子句的开头是and,where会把它去掉,where标签默认前缀会生成where关键字。
where标签:
解决if标签拼接字符串and符号问题
<select id="selectUserUseIf" resultType="User"
parameterType="User">
select * from user
<where>
<if test="u_sex!=null and u_sex!=''">
u_sex = #{u_sex}
</if>
<if test="u_cid!=null">
AND u_cid = #{u_cid}
</if>
</where>
</select>
trim标签:
可以定制where标签的规则:
<!--示例-->
<!--
prefix:可以在运行时替换<trim>为a
suffix:可以在运行时替换</trim>为b
prefixOverrides:如果子句前缀为c,可以在必要时自动去除,可以使用 | 分隔多个选项
suffixOverrides:如果子句后缀为c,可以在必要时自动去除,可以使用 | 分隔多个选项
-->
<trim prefix="a" suffix="b" prefixOverrides="c" suffixOverrides="d">
</trim>
set标签:
解决拼接字符串时逗号问题
set标签用来替代手写的set关键字,可以在必要时去掉子句末尾的逗号,用法和where标签类似。
foreach标签:
如果sql使用in,可以用该标签动态生成数组:
<!---->
<select id="selectUserUserIn" resultType="User">
select * from user u where u.`u_id` in
<!--如果传入的是List类型,则collection的值为list,如果是数组类型,则为array,如果时包装类,直接写引用名称-->
<!--foreach属性:
item:数组或集合的迭代值
separator:每两个迭代值中的分隔符
open:迭代开始时插入符号
close:迭代结束时插入符号
-->
<foreach collection="array" item="num" separator="," open="(" close=")">
#{num}
</foreach>
</select>
sql标签:
可以提取重复sql重用:
<!---->
<!--设置sql语句-->
<sql id="selectuser">
select * from user u
</sql>
<!--使用-->
<include refid="selectuser"></include>
mybatis中的Generator(MBG)
作用:根据数据库表自动自动生成Bean对象,java接口及SqlMapper.xml配置文件:
Generator的配置(generatorConfig.xml):
放在src目录下
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- -->
<!-- context为主要配置标签, targetRuntime为运行环境 -->
<context id="MyGenerator" targetRuntime="MyBatis3">
<!-- 可以让生成的代码简洁一点 -->
<commentGenerator>
<!-- 去掉注释 -->
<property name="suppressAllComments" value="true" />
<!-- 去掉时间戳 -->
<property name="suppressDate" value="true" />
</commentGenerator>
<!-- 数据库连接信息,配置连接数据库的必要信息 -->
<jdbcConnection
driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost/ssm_mybatis"
userId="root"
password="123456789">
</jdbcConnection>
<!-- javajdbc数据类型转换规则 ,设置为false则使用默认配置-->
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- javaModelGenerator:javabean配置
targetPackage:输出包名
targetProject:输出项目位置 -->
<javaModelGenerator targetPackage="com.echo.bean"
targetProject="src">
<!--enableSubPackages:是否开启子包名称 是否在包名后面架上scheme名称 -->
<property name="enableSubPackages" value="false" />
<!-- 在setter方法中加入trim,去掉空格 -->
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- mapper.xml配置,属性作用同上-->
<sqlMapGenerator targetPackage="com.echo.mapper"
targetProject="src">
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- java接口的配置,属性作用同上,type设置生成的文件类型为XML -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.echo.mapper" targetProject="src">
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- 数据表 要根据数据库中的表来生成,tableName:数据库中表的名称 -->
<table tableName="user"></table>
<table tableName="country"></table>
</context>
</generatorConfiguration>
调用配置文件(官方给出的代码,复制即可):
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("src/generatorConfig.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
在实体类的目录下会生成实体类的example类,其中封装了许多查询方式如:insert(完全插入数据)、insertSelective(带有判断的插入数据项)…
示例:
查询创建时间为null且姓名带有"老"的用户(selectByExample)
package test;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import com.echo.bean.User;
import com.echo.bean.UserExample;
import com.echo.mapper.UserMapper;
import utils.MybatisUtils;
public class Test {
public static void main(String[] args) {
SqlSession session = MybatisUtils.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
UserExample userExample = new UserExample();
//在createCriteria()下可以创建多种选择规则,且方法名称易于理解
userExample.createCriteria().andUCreatetimeIsNull().andUUsernameLike("%老%");
//直接将设置好条件的UserExample 示例传入方法selectByExample即可完成查询
List<User> list = mapper.selectByExample(userExample);
for(User u:list) {
System.out.println(u);
}
}
}