一、简介
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
对sql语句进行优化、修改比较困难的。
应用场景:
适用与需求变化不多的中小型项目,比如:后台管理系统,erp、orm、oa。。
mybatis:专注是sql本身,需要程序员自己编写sql语句,sql修改、优化比较方便。mybatis是一个不完全 的ORM框架,虽然程序员自己写sql,mybatis 也可以实现映射(输入映射、输出映射)。
应用场景:
适用与需求变化较多的项目,比如:互联网项目。
package cn.mycookies.mybatis.demo.po; import java.util.Date; public class User { private int id; private String username; private String sex; private Date birthday; private String address; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Date getBirthday() { return birthday; } public void setBirthday(Date date) { this.birthday = date; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "User [id=" + id + ", username=" + username + ", sex=" + sex + ", birthday=" + birthday + ", address=" + address + "]"; } }
<?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> <!-- 加载数据库配置文件 --> <properties resource="db.properties"> </properties> <!-- 配置数据库运行环境 --> <environments default="development"> <environment id="development"> <!-- 使用jdbc实务管理 实务和数据库连接池都是由mybatis --> <transactionManager type="JDBC"></transactionManager> <!-- 数据库 --> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </dataSource> </environment> </environments> <!-- 加载映射文件 --> <mappers> <mapper resource="mapper/UserMapper.xml"/> </mappers> </configuration>
2.配置映射文件
<?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="cn.mycookies.mybatis.demo.mapper.UserMapper"> <!--根据id查询User--> <select id="findUserById" parameterType="int" resultType="cn.mycookies.mybatis.demo.po.User"> SELECT * FROM USER WHERE id=#{id} </select> </mapper>
3.编写mapper.java接口在全局配置文件中加载映射文件
public interface UserMapper { //根据id查询 public User findUserById(int id) throws Exception; }
4.编写测试类
public class UserMapperTest { private SqlSessionFactory sqlSessionFactory= null; @Before public void setUp() throws Exception { //把配置文件加载到流中 InputStream config = Resources.getResourceAsStream("SqlMapConfig.xml"); //创建SqlSessionFactory对象 sqlSessionFactory=new SqlSessionFactoryBuilder().build(config); } @Test public void testFindUserById() throws Exception { //通过factory获取SqlSession对象 SqlSession session = sqlSessionFactory.openSession(); //创建mapper对象 UserMapper userMapper = session.getMapper(UserMapper.class); User user = userMapper.findUserById(1); System.out.println(user); } }
注:在xxxmapper.xml配置文件中parameterType指定输入参数类型,resultType指定输出结果类型
四、mybatis的两种开发模式
1mybatis的原始dao开发(麻烦,程序员需要写dao接口和dao的实现类)
思路:写出dao接口和实现类,并向dao中注入SqlSessionFactory,在执行CRUD操作前需要通过SqlSessionFactory对象创建SqlSession
dao接口
public interface UserDao { //根据id查询 public User findUserById(int id) throws Exception; //添加用户 public int insertUser(User user ) throws Exception; //删除用户信息 public void deleteUser(int id )throws Exception; }
实现类
注:当执行删除添加修改时需要手动提交实务
public class UserDaoImpl implements UserDao { //向dao注入SqlSessionFactory //通过构造方法注入 private SqlSessionFactory factory; public UserDaoImpl(SqlSessionFactory factory) { super(); this.factory = factory; } @Override public User findUserById(int id) throws Exception { SqlSession session = factory.openSession(); //第一个参数为名称空间和id第二个参数为查询传入的参数 User user = session.selectOne("test.findUserById",id); session.close(); return user; } @Override public int insertUser(User user) throws Exception { SqlSession session = factory.openSession(); session.insert("test.addUser", user); session.commit(); session.close(); return user.getId(); } @Override public void deleteUser(int id) throws Exception { SqlSession session = factory.openSession(); session.delete("test.deleteUser", id); session.commit(); session.close(); } }
测试代码
public class UserDaoImplTest { private SqlSessionFactory sqlSessionFactory= null; @Before public void setUp() throws Exception { InputStream config = Resources.getResourceAsStream("SqlMapConfig.xml"); sqlSessionFactory=new SqlSessionFactoryBuilder().build(config); } @Test public void test() throws Exception { //创建userdao对象 UserDao dao = new UserDaoImpl(sqlSessionFactory); User user = dao.findUserById(1); System.out.println(user); } }
总结
1、dao接口实现类方法中存在大量模板方法,设想能否将这些代码提取出来,大大减轻程序员的工作量。
2、调用sqlsession方法时将statement的id硬编码了
3、调用sqlsession方法时传入的变量,由于sqlsession方法使用泛型,即使变量类型传入错误,在编译阶段也不报错,不利于程序员开发。
<mapper namespace="cn.mycookies.mybatis.demo.mapper.UserMapper">
b.mapper.java接口类中的方法名和mapper.java中对应的statement的id一致
c.mapper.java接口 中的返回值和参数与mapper.xml中的resultType和parameterType一致
注:当遵守以上开发规范时mybatis会对具体类的实现自动生成
五、MyBatis的开发使用
mapper.xml配置文件
1.自增主键返回
场景:数据库表设置主键自增长,当插入一个新的对象时,执行insert之前自动生成一个自增主键,要求返回该主键。
可用此函数来获取: LAST_INSERT_ID()。想要完成此功能需要在mapper.xml
配置文件中对sql操作进行配置
<insert id="addUser" parameterType="cn.mycookies.mybatis.demo.po.User"> <!-- 插入之后返回主键(自动生成)只适用于自增主键 key+Property指的是将查询到的主键设置到parameType指定对象的那个属性 resultType:指定结果类型 --> <selectKey keyProperty="id" resultType="java.lang.Integer" order="AFTER"> SELECT LAST_INSERT_ID() </selectKey> <!-- 使用mysql的uuid()生成主键 首先查询uuid得到主键 将主键设置到user对象中 <selectKey keyProperty="id" resultType="String" order="BEFORE"> SELECT uuid() </selectKey> --> INSERT INTO USER(id,username,birthday,sex,address) values(#{id},#{username},#{birthday},#{sex},#{address}) </insert>
2.模糊查询
mapper.xml配置文件中statement的配置
<select id="findUserByName" parameterType="String" resultType="cn.mycookies.mybatis.demo.po.User"> <!-- SELECT * FROM USER WHERE username like #{value} $符号表示拼接字符串,将接受到的内容不加任何修饰的拼接到sql中 可能会引起sql注入 大括号内只能使用value --> SELECT * FROM USER WHERE username like '%${value}%' </select>
3.#{}和${}的区别
#{}表示一个占位符号,#{}接收输入参数,类型可以是简单类型,pojo、hashmap。
如果接收简单类型,#{}中可以写成value或其它名称。
#{}接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性...的方式获取对象属性值。
${}表示一个拼接符号,会引用sql注入,所以不建议使用${}。
${}接收输入参数,类型可以是简单类型,pojo、hashmap。
如果接收简单类型,${}中只能写成value。
${}接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性...的方式获取对象属性值。
4.selectOne 和selectList(指的是mapper.java接口中返回值类型的配置)
selectonse表示查询一条记录进行映射,如果selectOne映射成功,selectList也可以映射。
selectList表示查询多天记录进行映射。如果使用selectList查询多条记录,不能使用selectOne.
SqlMapConfig.xml-mybatis的全局配置文件
mybatis的全局配置文件SqlMapConfig.xml配置文件包括一下内容
properties:属性
setting:全局参数设置
typeAliases:类型别名
typeHandlers:类型处理器
objectFactory:对象工厂
environments:环境集合属性对象
environment:环境子属性对象
transactionManager:实务管理
dataSource:数据库源的配置
mappers:映射器
1.properties
场景:将数据库参数单独提取出来配置到db.properties的配置文件中,只需要使用properties将db.properties里面的属性值加载到SqlMapConfig.xml中即可!方便对参数的统一管理,其他的配置文件都可以引用此配置文件。
db.properties
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mybatis2 jdbc.username=root jdbc.password=password
SqlMapConfig.xml
<!-- 加载数据库配置文件 --> <properties resource="db.properties"> </properties> <!-- 配置数据库运行环境 --> <environments default="development"> <environment id="development"> <!-- 使用jdbc实务管理 实务和数据库连接池都是由mybatis --> <transactionManager type="JDBC"></transactionManager> <!-- 数据库 --> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </dataSource> </environment> </environments>
注:MyBatis将按照下面的顺序来加载属性
》在properties元素体内定义的属性》properties元素中通过resource或url引用的属性》parameterType传递的属性
在加载过程中会覆盖同名属性,建议不要在properties元素内添加任何属性值,直接爱那个属性值定义在properties文件中,为了防止命名重复,在properties文件中定义属性名要有一定地特殊性,如:jdbc.url (尽量不要直接定义为url)
2.settiong
mybatis框架运行时可以调整一些默认的运行参数,通过该属性配置后进而影响mybatis的运行行为。
如:开启二级缓存,开启延迟加载。
3.typeAliases
场景:在mapper.xml中的statement中需要配置parameterType和resultType(参数类型和结果类型),在配置中通常需要指定类型的全路径,优化这一现象,通过在mapper.xml定义别名即可。
a.对于基本数据类型以及他们的封装类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 |
b.自定义别名
b.1单个别名定义
<typeAliases> <!--type:表示类的路径,alias:类的别名--> <typeAlias type="cn.mycookies.mybatis.demo.po.User" alias="user"/> </typeAliases>
b.2批量定义别名(常用)
<typeAliases>
<!--name指定包名,该包下的所有类都被定义了别名,为类名,首字母大小写都可以--> <package name="cn.mycookies.mybatis.demo.po"/> </typeAliases>
别名的引用:在需要使用的地方直接通过定义的别名直接引用即可。
4.typeHandlers
该标签用来处理jdbc类型和java类型之间的转换,但是通常情况下mybatis默认进行的转换已经满足日常开发,不需要自定义
类型处理器 |
Java类型 |
JDBC类型 |
BooleanTypeHandler |
Boolean,boolean |
任何兼容的布尔值 |
ByteTypeHandler |
Byte,byte |
任何兼容的数字或字节类型 |
ShortTypeHandler |
Short,short |
任何兼容的数字或短整型 |
IntegerTypeHandler |
Integer,int |
任何兼容的数字和整型 |
LongTypeHandler |
Long,long |
任何兼容的数字或长整型 |
FloatTypeHandler |
Float,float |
任何兼容的数字或单精度浮点型 |
DoubleTypeHandler |
Double,double |
任何兼容的数字或双精度浮点型 |
BigDecimalTypeHandler |
BigDecimal |
任何兼容的数字或十进制小数类型 |
StringTypeHandler |
String |
CHAR和VARCHAR类型 |
ClobTypeHandler |
String |
CLOB和LONGVARCHAR类型 |
NStringTypeHandler |
String |
NVARCHAR和NCHAR类型 |
NClobTypeHandler |
String |
NCLOB类型 |
ByteArrayTypeHandler |
byte[] |
任何兼容的字节流类型 |
BlobTypeHandler |
byte[] |
BLOB和LONGVARBINARY类型 |
DateTypeHandler |
Date(java.util) |
TIMESTAMP类型 |
DateOnlyTypeHandler |
Date(java.util) |
DATE类型 |
TimeOnlyTypeHandler |
Date(java.util) |
TIME类型 |
SqlTimestampTypeHandler |
Timestamp(java.sql) |
TIMESTAMP类型 |
SqlDateTypeHandler |
Date(java.sql) |
DATE类型 |
SqlTimeTypeHandler |
Time(java.sql) |
TIME类型 |
ObjectTypeHandler |
任意 |
其他或未指定类型 |
EnumTypeHandler |
Enumeration类型 |
VARCHAR-任何兼容的字符串类型,作为代码存储(而不是索引)。 |
5.mapper
该标签用于加载mapper.xml配置文件,可以单个加载也可以个批量加载。
<!-- 加载映射文件 --> <mappers> <!-- <mapper resource="sqlmap/User.xml" /> --> <!-- <mapper resource="mapper/UserMapper.xml"/> --> <!-- 通过mapper接口加载配置文件 遵守一些规范:需要将mapper.java接口类名称和mapper.xml文件保持一致 ,且在一个目录中 前提:使用mapper代理的方式 <mapper class="cn.mycookies.mybatis.demo.mapper.UserMapper"/> --> <!-- 批量加载 推荐使用 name:指定mapper.xml配置文件所在的包名 --> <package name="cn.mycookies.mybatis.demo.mapper"/> </mappers>