Mybatis其实就是ORM。
ORM作用:实现对象和表之间的映射,对对象的操作会转换成对表的操作。
一, Mybatis入门实例
1) 导入Mybatis的jar包;
mybatis-3.2.8.jar
mysql-connector-java-5.1.18-bin2.jar
2) 创建实体;一个表对应着一个实体。实体名对应着表名,属性对应着表的字段;
package entity;
public class User {
private int id;
private String username;
private String password;
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 getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
3):创建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 id="development">
<transactionManager type="JDBC">
</transactionManager>
<dataSource type="UNPOOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/imooc"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
</configuration>
4):创建一个映射文件,定义SQL命令,指定查询结果与对象的映射,如果表字段与实体属性名字相同,Mybatis会自动进行映射;
<?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="entity.userMapper">
<select id = "selectUser" resultType = "entity.User">
select * from user where id = #{id}
</select>
</mapper>
5):在配置文件中加载映射文件;
<?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 id="development">
<transactionManager type="JDBC">
<property name="" value=""/>
</transactionManager>
<dataSource type="UNPOOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/imooc"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource = "entity/userMapper.xml"/>
</mappers>
</configuration>
6):调用Mybatis的API访问数据库;
package util;
import java.io.IOException;
import java.io.Reader;
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 MybatisUtil {
//创建SqlSessionFactory,以及获得SqlSession
public static SqlSession getSqlSession() throws IOException {
// 通过配置文件获取数据库连接信息
Reader reader = Resources.getResourceAsReader("config/Configuration.xml");
// 通过配置信息构建一个SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
// 通过sqlSessionFactory打开一个数据库会话
SqlSession sqlSession = sqlSessionFactory.openSession();
return sqlSession;
}
}
7)测试:
public class Test {
public static void main(String[] args) throws IOException {
SqlSession sqlSession = MybatisUtil.getSqlSession();
User user = sqlSession.selectOne("entity.userMapper.selectUser", 1);
System.out.println("id = "+ user.getId()
+ ", username = " + user.getUsername()
+ ", password = " + user.getPassword());
sqlSession.close();
}
}
二, Mybatis配置文件详解
2.1 properties:加载属性文件
<!-- 加载属性文件 -->
<properties resource="jdbc.properties"></properties>
加载 jdbc.properties 文件后,可以在Mybatis配置文件中使用${属性名}方式访问属性文件中的属性信息。例如:
<!-- 连接数据库驱动 -->
<property name="driver" value="${driverClassName}" />
<!-- 连接数据库URL -->
<property name="url" value="${jdbcUrl}" />
<!-- 连接数据库用户名 -->
<property name="username" value="${username}" />
<!-- 连接数据库密码 -->
<property name="password" value="${password}" />
2.2 typeAliases:指定类型别名
<!-- 指定对象的别名 -->
<typeAliases>
<typeAlias type="com.chinasofti.beans.Product" alias="productAlia"/>
</typeAliases>
指定类型别名后,可以在映射文件的参数类型和返回结构类型中使用别名。
<select id="findAll" resultType="productAlia">
select * from product
</select>
2.3 enviorments:配置Mybatis运行环境
<!-- 配置MyBatis的环境 -->
<environments default="dev">
<!-- 配置一个环境 -->
<environment id="dev">
<!-- 配置事务管理器 JDBC(有事务)、MANAGED(托管) -->
<transactionManager type="JDBC" />
<!-- 配置数据源 JNDI(web服务器方式定义数据源)、POOLED(自带连接池)、UNPOOLED(不带连接池) -->
<dataSource type="POOLED">
<!-- 连接数据库驱动 -->
<property name="driver" value="${driverClassName}" />
<!-- 连接数据库URL -->
<property name="url" value="${jdbcUrl}" />
<!-- 连接数据库用户名 -->
<property name="username" value="${username}" />
<!-- 连接数据库密码 -->
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
一个environment配置一个运行环境。在实际开发中,一般都会把开发环境和生产环境分开配置。
2.4 mappers:加载映射文件。
<mappers>
<mapper resource="com/chinasofti/beans/ProductMapper.xml"/>
</mappers>
三, ${}和#{}的区别
1):在预编译的时候,Mybatis会${属性名}中的内容简单替换具体的属性值,PrepardStatement对象进行预编译的时候会把#{属性值}替换成问号;
2):#{属性名}可以防止SQL注入;而${属性名}可能会引发SQL注入的安全问题。
四, 动态SQL命令
动态SQL命令可以在SQL命令中加入业务逻辑控制。动态SQL语句就是在程序运行的时候才对SQL命令进行编译和运行。
4.1 <where>和<if>
where:动态添加where标签;
if:判断条件是否成立,如果条件成立才添加SQL命令,否则不添加;
<select id="findAll" parameterType="productAlia" resultType="productAlia">
select * from product
<where>
<if test="name != '' and name != null">
name like CONCAT('%', #{name}, '%')
</if>
</where>
</select>
注意:if标签的test属性值也是ognl表达式,但是可以不写#{}
4.2 <sql>
作用:定义一个SQL命令,可以被其他标签引用,可以提高SQL命令的重用性。
命令格式:
<sql id="sql标识">
sql命令
</sql>
引用SQL:
<include refid="sql标识"></include>
4.3 <foreach>标签
作用:循环生成SQL命令
命令格式:
<foreach collection="数组或集合" open="" close="" separator="" item=""></foreach>
collection:传入参数名。该参数可以是数组,也可以是集合类型,必选;
open:表示该SQL语句以什么开始,可选;
close:表示该SQL语句以什么结束,可选;
separate:Mybatis会在每次迭代时候给SQL语句添加separate属性指定的字符,可选;
item:指定访问集合元素的名字;
index:表示当前迭代的索引值,可选。
例如:
<select id="delete" resultMap="productResultMap">
delete from product
<where>
product_id in
<foreach collection="productIds" open="(" close=")" separator="," item="productId">
${productId}
</foreach>
</where>
</select>
五, 接口映射
5.1 实现接口映射
接口映射的要求是什么?
1)接口的方法名与SQL的id属性相同;
2)调用session的getMapper方法,获取映射接口的代理对象;
3)Mapper配置文件的命名空间的名字必须与接口的完整名字(包名+接口名)相同;
4)接口方法的参数类型必须要与SQL命令的参数类型相同;
5)接口方法的返回值类型要与SQL命令的返回结果类型相同。
实现接口映射的步骤:
1):定义一个接口类,提供一个接口方法,该方法的名字与SQL命令的id相同;
2):修改映射文件的命名空间名字。命名空间名字要与接口名相同;
3):调用session的getMapper方法获取映射接口的代理对象;
4):调用接口方法;
5):提交事务;
6):关闭资源;
package com.chinasofti.demo02接口映射;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import com.chinasofti.beans.Product;
import com.chinasofti.mapper.ProductMapper;
import com.chinasofti.utils.MyBatisUtil;
public class Demo02 {
public static void main(String[] args) {
// 获取SqlSession对象
SqlSession session = MyBatisUtil.getSession();
// 调用session对象的getMapper方法获取映射接口的代理对象。
ProductMapper productMapper = session.getMapper(ProductMapper.class);
// 调用接口对象的方法
Product product = new Product();
product.setName("积木");
List<Product> productList = productMapper.findAll(product);
// 遍历集合
for (Product p : productList) {
System.out.println(p);
}
// 提交事务
session.commit();
// 关闭资源
session.close();
}
}
六,Mybatis注解
6.1 基本注解
@Select:定义select命令。
@Insert:定义insert命令。
@update:定义update命令。
@delete:定义delete命令。
public interface ProductMapper {
@Select("select * from product")
List<Product> findAll(Product product);
@Insert("insert into product(name, price) values(#{name}, #{price})")
void addProduct(Product product);
@Update("update product set price = #{price} where id = #{id}")
void updateProduct(Product product);
@Delete("delete from product where id = #{id}")
void deleteProduct(int id);
}
使用注解,就不需要在XxxMapper.xml文件中定义SQL命令。
定义完成后,需要Mybatis配置文件中加载映射接口。
<mappers>
<mapper class="com.chinasofti.mapper.ProductMapper"/>
</mappers>
测试:
package com.chinasofti.demo02接口映射;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import com.chinasofti.beans.Product;
import com.chinasofti.mapper.ProductMapper;
import com.chinasofti.utils.MyBatisUtil;
public class Demo02 {
public static void main(String[] args) {
testDelete();
}
private static void testDelete() {
// 获取SqlSession对象
SqlSession session = MyBatisUtil.getSession();
// 调用session对象的getMapper方法获取映射接口的代理对象。
ProductMapper productMapper = session.getMapper(ProductMapper.class);
// 调用接口对象的方法
productMapper.deleteProduct(8);
// 提交事务
session.commit();
// 关闭资源
session.close();
System.out.println("删除成功!");
}
private static void testUpdate() {
// 获取SqlSession对象
SqlSession session = MyBatisUtil.getSession();
// 调用session对象的getMapper方法获取映射接口的代理对象。
ProductMapper productMapper = session.getMapper(ProductMapper.class);
// 调用接口对象的方法
Product product = new Product();
product.setId(8);
product.setPrice(199);
productMapper.updateProduct(product);
// 提交事务
session.commit();
// 关闭资源
session.close();
System.out.println("修改成功!");
}
private static void testInsert() {
// 获取SqlSession对象
SqlSession session = MyBatisUtil.getSession();
// 调用session对象的getMapper方法获取映射接口的代理对象。
ProductMapper productMapper = session.getMapper(ProductMapper.class);
// 调用接口对象的方法
Product product = new Product();
product.setName("坦克");
product.setPrice(1999);
productMapper.addProduct(product);
// 提交事务
session.commit();
// 关闭资源
session.close();
System.out.println("添加成功!");
}
private static void testFind() {
// 获取SqlSession对象
SqlSession session = MyBatisUtil.getSession();
// 调用session对象的getMapper方法获取映射接口的代理对象。
ProductMapper productMapper = session.getMapper(ProductMapper.class);
// 调用接口对象的方法
Product product = new Product();
product.setName("积木");
List<Product> productList = productMapper.findAll(product);
// 遍历集合
for (Product p : productList) {
System.out.println(p);
}
// 提交事务
session.commit();
// 关闭资源
session.close();
}
}
6.2 映射结果
@ResultType:指定结果类型
@Results:自定义结果映射
@Result:指定表的字段与实体属性的映射关系
@Select("select * from product")
// @ResultType(Product.class)
@Results({
@Result(column="id", property="id"),
@Result(column="name", property="name"),
@Result(column="price", property="price")
})
List<Product> findAll(Product product);
如果查询结果的字段名与实体的属性名字相同的时候,可以不需要指定结果的类型,它会自动进行映射。
如果查询结果的字段名与实体的属性名不相同,那么久需要自定义结果映射。
@SelectKey
@SelectKey(before = true|false,
keyProperty = "实体属性",
keyColumn = "主键列",
resultType = 映射结果的类型,
statement="获取主键的sql"
before:指定在插入前或插入后执行statement语句。
statement:获取插入数据的id。
keyProperty:实体的id属性。
keyColumn:表的主键列。
resultType:返回结果类型。
例如:
@Insert("insert into product(product_name, product_price) values(#{name}, #{price})")
@SelectKey(
before = false,
keyProperty = "id",
keyColumn = "product_id",
resultType = Integer.class,
statement = { "select last_insert_id()" })
public int insert(Product product);
6.3 在注解中使用动态SQL
如果需要在注解中使用动态SQL,那么SQL命令需要放在script中定义。
举例(动态添加查询条件):
@Select("<script>"
+ "select * from product"
+ "<where>"
+ " <if test=\"name != null and name != ''\">"
+ " name like CONCAT('%', #{name}, '%')"
+ " </if>"
+ "</where>"
+ "</script>")
List<Product> findAll(Product product);
举例(删除多条记录):
@Delete({
"<script>delete from product where product_id in " +
"<foreach collection=\"ids\" item = \"id\" open=\"(\" separator=\",\" close=\")\">" +
"#{id}" +
"</foreach>" +
"</script>"
})
void deleteProducts(int[] ids);