1.数据库环境切换(驱动jar)
a、切换environment
//db.properties
#oracle
oracle.driver=oracle.jdbc.OracleDriver
oracle.url=jdbc:oracle:thin:@127.0.0.1:1521:ORCL
oracle.username=root
oracle.password=123456
#mysql
mysql.driver=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf8
mysql.username=root
mysql.password=123456
注意:db.properties里面要检查空格,如果有多余的空格会报错
//在config.xml中
<properties resource="db.properties" />
<!-- default和id值相同时才能连接成功,测试类中也可以修改默认值 -->
<environments default="devMysql">
<!-- 开发环境(自己的计算机) -->
<environment id="devOracle">
<!-- 事务提交方式:
JDBC:利用JDBC方式处理事务(手工)
MANAGED:将事务交由其他组件去托管(spring,jobss)默认会关闭连接
-->
<transactionManager type="JDBC" />
<!-- 取消MANAGED的默认关闭连接 -->
<!-- <property name="closeConnection" value="false" /> -->
<!-- 数据源类型:
POOLED:使用数据库连接池(三方)
UNPOOLED:传统的JDBC模式,每次访问数据库,均需要打开、关闭等数据库操作,比较消耗性能
JNDI:从tomcat中获取一个内置的数据库连接池
-->
<dataSource type="POOLED">
<!-- 配置数据库信息 -->
<property name="driver" value="${oracle.driver}" />
<property name="url" value="${oracle.url}" />
<property name="username" value="${oracle.username}" />
<property name="password" value="${oracle.password}" />
</dataSource>
</environment>
<!-- 真正的项目应该在 发布的那台计算机上运行 -->
<environment id="devMysql">
<!-- 数据库事务处理 -->
<transactionManager type="JDBC" />
<!-- 配置数据库信息 -->
<dataSource type="POOLED">
<property name="driver" value="${mysql.driver}" />
<property name="url" value="${mysql.url}" />
<property name="username" value="${mysql.username}" />
<property name="password" value="${mysql.password}" />
</dataSource>
</environment>
</environments>
b、配置Provider别名
<!-- 配置数据库支持类 -->
<databaseIdProvider type="DB_VENDOR">
<!-- value是别名 -->
<property name="MySQL" value="mysql"/>
<property name="Oracle" value="oracle"/>
<property name="SQL Server" value="sql server"/>
</databaseIdProvider>
c、写不同数据库的SQL语句
d、在xxxMapper.xml中配置databaseId=“mysql”
<select id="queryPersonByIdWithConverter" resultMap="personResult" parameterType="int" databaseId="oracle">
select * from Person where id = #{id}
</select>
<select id="queryPersonByIdWithConverter" resultMap="personResult" parameterType="int" databaseId="mysql">
select * from Person where id = #{id}
</select>
如果xxxMapper.xml的sql标签仅有一个不带databaseId的标签,则该标签会自动适应当前数据库
如果既有不带,又有带databaseId标签的sql,则程序会优先使用带databaseId的标签
2.注解方式(小项目)
推荐使用xml
a、将SQL语句写在接口的方法上面的注解
//xxxMapper.java
//操作mybatis的接口
public interface PersonMapper {
/* 1、方法名和mapper.xml文件中标签的id相同
* 2、方法的输入参数和mapper.xml文件中标签的parameterType一致
* 3、方法的返回值和mapper.xml文件中标签的resultType一致
* 4、接口里的方法默认public abstract,所以可以省略
*/
@Select("select * from person ")
List<Person> queryPersonByIdWithOneToOneAndLazyLoad();
}
b、将接口的全类名写入< mapper>,让mybatis知道sql语句此时是储存在接口中
<mappers>
<!-- 加载映射文件 -->
<mapper class="org.lanqiao.mapper.PersonMapper"/>
<!-- <mapper resource="org/lanqiao/mapper/personMapper.xml" /> -->
</mappers>
注解/xml都支持批量引入
<mappers>
<!-- 加载映射文件 -->
<!-- 可以将org.lanqiao.mapper包中所有的注解接口和xml全部一次性引入 -->
<package name="org.lanqiao.mapper"/>
<!-- <mapper class="org.lanqiao.mapper.PersonMapper"/> -->
<!-- <mapper resource="org/lanqiao/mapper/personMapper.xml" /> -->
</mappers>
3.增删改的返回值(不包括查)
返回值可以使void、Integer、Boolean…
操作:只需要在接口中修改,不需要在xml文件中操作
4.事务自动提交
手动提交(推荐):
SqlSession session = sessionFactory.openSession();
//手动提交
session.commit();
自动提交(增删改):
SqlSession session = sessionFactory.openSession(true);
5.自增
MySQL支持自增,Oracle不支持自增
对于支持自增的MySQL,只需要在插入语句中加入useGeneratedKeys="true" keyProperty="id"
keyProperty值为数据库中的自增字段名
//xxxMapper.xml
<insert id="addPersonWithConverter" parameterType="Person" useGeneratedKeys="true" keyProperty="id">
insert into person(id,name,age,sex) values(#{id},#{name},#{age},#{sex,javaType=boolean,jdbcType=INTEGER})
</insert>
//测试类方法
public static void addPersonWithConverter(Person person) throws IOException {
//加载Mybatis配置文件(为了访问数据库)
Reader reader = Resources.getResourceAsReader("config.xml");
//可以在build中修改config.xml中developments的默认值
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader,"devMysql");
//session - connection
SqlSession session = sessionFactory.openSession();
PersonMapper personMapper=session.getMapper(PersonMapper.class);
//接口中的方法--》SQL语句
personMapper.addPersonWithConverter(person);
System.err.println(person.getId());
//提交事务,不然数据进不去数据库中
session.commit();
session.close();
}
public static void main(String[] args) throws IOException {
addPersonWithConverter(new Person(null,"cxx",11,true));
}
如果不修改SQL语句,则输出null,修改后输出数据库中对应的id值
对于Oracle不支持自增:通过序列模拟实现
create sequence seq increment by 1 start with 1;
序列的两个属性:
nextval:序列中下一个值
currval:当前值
insert into person values(seq.nextval,"cxx",11,true);
//xxxMapper.xml
//方式一:
<insert id="addPersonWithConverter" parameterType="Person">
<selectKey keyProperty="id" resultType="Integer" order="BEFORE">
select seq.nextval from dual
</selectKey>
insert into person(id,name,age,sex) values(#{id},#{name},#{age},#{sex,javaType=boolean,jdbcType=INTEGER})
</insert>
//方式二:
<insert id="addPersonWithConverter" parameterType="Person">
<selectKey keyProperty="id" resultType="Integer" order="AFTER">
select seq.currval from dual
</selectKey>
insert into person(id,name,age,sex) values(seq.nextval,#{name},#{age},#{sex,javaType=boolean,jdbcType=INTEGER})
</insert>
6.参数
目前将多个参数封装到一个JavaBean对象(pojo),然后使用该对象传递
传入多个参数时,不用在xxxMapper.xml中编写parameterType。
//xxxMapper.xml
<!--
<insert id="addPersonWithConverter" parameterType="Person" useGeneratedKeys="true" keyProperty="id">
insert into person(id,name,age,sex) values(#{id},#{name},#{age},#{sex,javaType=boolean,jdbcType=INTEGER})
</insert>
-->
<insert id="addPersonWithConverter" useGeneratedKeys="true" keyProperty="id">
insert into person(id,name,age,sex) values(#{id},#{name},#{age},#{sex,javaType=boolean,jdbcType=INTEGER})
</insert>
//xxxMapper.java
import org.apache.ibatis.annotations.Param;
import org.lanqiao.entity.Person;
//操作mybatis的接口
public interface PersonMapper {
/* 1、方法名和mapper.xml文件中标签的id相同
* 2、方法的输入参数和mapper.xml文件中标签的parameterType一致
* 3、方法的返回值和mapper.xml文件中标签的resultType一致
* 4、接口里的方法默认public abstract,所以可以省略
*/
void addPersonWithConverter(Person person);
void addPersonWithConverter(@Param("id")Integer id,@Param("name")String name,@Param("age")int age,@Param("sex")boolean sex);
}
//测试类方法
public static void addPersonWithConverter(Integer id,String name,int age,boolean sex) throws IOException {
//加载Mybatis配置文件(为了访问数据库)
Reader reader = Resources.getResourceAsReader("config.xml");
//可以在build中修改config.xml中developments的默认值
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader,"devMysql");
//session - connection
SqlSession session = sessionFactory.openSession();
PersonMapper personMapper=session.getMapper(PersonMapper.class);
//接口中的方法--》SQL语句
personMapper.addPersonWithConverter(id,name,age,sex);
System.err.println(id);
//提交事务,不然数据进不去数据库中
session.commit();
session.close();
}
public static void main(String[] args) throws IOException {
addPersonWithConverter(null,"cxx",11,true);
}
参数中既有简单类型也有对象类型
//xxxMapper.java
import org.apache.ibatis.annotations.Param;
import org.lanqiao.entity.Person;
//操作mybatis的接口
public interface PersonMapper {
/* 1、方法名和mapper.xml文件中标签的id相同
* 2、方法的输入参数和mapper.xml文件中标签的parameterType一致
* 3、方法的返回值和mapper.xml文件中标签的resultType一致
* 4、接口里的方法默认public abstract,所以可以省略
*/
void addPersonWithConverter(Person person);
void addPersonWithConverter(@Param("id")Integer id,@Param("name")String name,@Param("age")int age,@Param("sex")boolean sex);
void addPersonWithConverter(@Param("id")Integer id,@Param("per")Person person);
}
//xxxMapper.xml
<!--
<insert id="addPersonWithConverter" parameterType="Person" useGeneratedKeys="true" keyProperty="id">
insert into person(id,name,age,sex) values(#{id},#{name},#{age},#{sex,javaType=boolean,jdbcType=INTEGER})
</insert>
<insert id="addPersonWithConverter" useGeneratedKeys="true" keyProperty="id">
insert into person(id,name,age,sex) values(#{id},#{name},#{age},#{sex,javaType=boolean,jdbcType=INTEGER})
</insert>
-->
<insert id="addPersonWithConverter" useGeneratedKeys="true" keyProperty="id">
insert into person(id,name,age,sex) values(#{id},#{per.name},#{per.age},#{per.sex,javaType=boolean,jdbcType=INTEGER})
</insert>
7.增加null
Oracle:如果插入的字段是Null,提示错误:Other而不是null
MySQL:如果插入的字段是Null(没有约束),可以正常执行
原因:各个数据库在MyBatis中对各种数据类型的默认值不一致。MyBatis中,jdbcTypeForNull(如果是Null),则默认值为Other。对于Other,MySQL能够处理(NULL),但是Oracle不行
解决:Oracle:null --> OTHER,需要手工告诉Oracle:other --> null
a、当某个数据类型Oracle无法处理时,告诉它用默认值null;注意,此时设置的jdbcType=NULL不会影响正常的赋值
<insert id="addPerson" databaseId="oracle">
insert into person(id,name) values(#{id},#{name,jdbcType=NULL})
</insert>
b、配置MyBatis全局配置文件config.xml(推荐)
<settings>
<setting name="jdbcTypeForNull" value="NULL"/>
</settings>
8.返回值为HashMap
<!-- resultType为HashMap -->
<!-- 别名作为map的key -->
<!-- 动态SQL -->
<!-- 在where后面加1=1或者使用<where>标签解决and问题,<where>标签会自动处理第一个and -->
<select id="queryAllPersonByNameOrAgeWithSQLTag" parameterType="Person" resultType="HashMap" >
select id "perid",name "pername" from Person
<where>
<if test="name!=null and name!='' ">
and name=#{name}
</if>
<if test="age!=null and age!=0 ">
and age=#{age}
</if>
</where>
</select>
其中id是数据库的字段名,"perid"是id的别名,用于在map中取值时使用(作为map的key)。map.get(“perid”)
如果不加别名,map的key就是字段名
@MapKey("ID")//oracle的元数据(字段名、表名)都是大写
HashMap<Integer,Person> queryPersonsByHashMap();
<select id="queryPersonByHashMap" resultType="HashMap">
select id,name,age from person
</select>
程序根据select的返回值知道map的value就是Person,根据@MapKey("ID")
知道map的key是id
9.ResultMap
如果数据库的字段名和JavaBean的属性名不一致时,可以使用ResultMap进行对应。
在ResultMap中,还可以使用鉴别器:对相同SQL中不同字段值进行判断,从而进行不同的处理。
<!-- 一对一和延迟加载 -->
<select id="queryPersonByIdWithOneToOneAndLazyLoad" parameterType="int" resultMap="Person_PersonCard_lazyLoad" databaseId="mysql">
select * from person
</select>
<resultMap type="Person" id="Person_PersonCard_lazyLoad">
<!-- 分为主键id和非主键result -->
<id property="id" column="id" />
<!-- <result property="name" column="name" /> -->
<!-- 鉴别器:对查询结果进行分支处理:如果是a年级则真名,如果b年级则昵称 -->
<discriminator javaType="String" column="className">
<case value="a" resultType="Person">
<result column="name" property="name" />
</case>
<!-- resultType值与此resultMap的type一致 -->
<case value="b" resultType="Person">
<result column="nickName" property="name" />
</case>
</discriminator>
<result property="age" column="age" />
<!-- jdbcType的值要大写 -->
<result property="sex" column="sex" javaType="boolean" jdbcType="INTEGER" />
<!-- 一对一时,对象成员使用association映射 -->
<!-- 采用延迟加载:在查询学生是,并不立即加载学生证信息 -->
<association property="personCard" javaType="PersonCard" select="org.lanqiao.mapper.PersonCardMapper.queryCardById" column="cardId">
<!-- <id property="cardId" column="cardId" />
<result property="cardInfo" column="cardInfo" /> -->
</association>
</resultMap>
10.别名
//在config.xml中
<!-- 设置单个/多个别名(别名忽略大小写) -->
<typeAliases>
<!-- 设置单个别名 -->
<!-- <typeAlias type="org.lanqiao.entity.Person" alias="Person"/> -->
<!-- 批量设置别名,以下会自动将该包(和子包)中的所有类批量定义别名:别名就是类名 -->
<package name="org.lanqiao.entity"/>
</typeAliases>
如果在批量设置别名是,出现了冲突。例如org.lanqiao.entity包中有个Person类,而org.lanqiao.entity包的子包org.lanqiao.entity.mybatis包中也有个Person类;则可以使用@Alias(“myPerson”)区分
@Alias("myPerson")
public class Person implements Serializable{
}
11.trim标签
<where>
可以处理拼接SQL中开头第一个and
<trim>
可以处理拼接SQL中开头或结尾第一个and
<trim prefix="where" prefixOverrides="and"></trim>
prefix="where"
给拼接的SQL拼接一个where
prefixOverrides="and"
处理拼接SQL中开头,第一个and
suffixOverrides="and"
处理拼接SQL中结尾,最后一个and
prefix
拼接prefixOverrides
删除,如果有则删除
12.内置参数
_parameter:代表mybatis的输入参数
_databaseId:代表当前数据库名字
例如:在下面例子中if标签中test即可以使用name,因为name是parameterType值Person的属性,也可以使用_parameter.name
<!-- resultType为HashMap -->
<!-- 别名作为map的key -->
<!-- 动态SQL -->
<!-- 在where后面加1=1或者使用<where>标签解决and问题,<where>标签会自动处理第一个and -->
<select id="queryAllPersonByNameOrAgeWithSQLTag" parameterType="Person" resultType="HashMap" >
select id "id",name "name" from Person
<where>
<if test="name!=null and name!='' ">
and name=#{name}
</if>
<if test="age!=null and age!=0 ">
and age=#{age}
</if>
</where>
</select>
13.模糊查询
a、${}:原样输出
select * from Person where name like '%${name}%'
b、传值时
//测试类中
person.setName("%c%");
//xxxMapper.xml中
select * from Person where name like #{name}
c、bind参数
通过bind将传入的name进行了处理
//在xxxMapper.xml中
<select id="queryPersonByNameOrAgeWithHashMap" parameterType="HashMap" resultType="Person">
<bind name="_queryName" value="'%'+name+'%'"/>
select * from Person where name like #{_queryName} or age=#{age}
</select>