简单使用mybatis的增删改查
通过id查找到用户
使用的sql:
SELECT * FROM `user` WHERE id = 1
在user.xml中添加select标签,编写sql:
<?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">
<!-- namespace:命名空间-->
<mapper namespace="test">
<!-- id:statement的id 或者叫做sql的id-->
<!-- parameterType:声明输入参数的类型 -->
<!-- resultType:声明输出结果的类型,应该填写pojo的全路径 -->
<!-- #{}:输入参数的占位符,相当于jdbc的? -->
<select id="queryUserById" parameterType="int"
resultType="cn.itcast.mybatis.pojo.User">
SELECT * FROM `user` WHERE id = #{id}
</select>
</mapper>
测试程序步骤:
1. 创建SqlSessionFactoryBuilder对象
2. 加载SqlMapConfig.xml配置文件
3. 创建SqlSessionFactory对象
4. 创建SqlSession对象
5. 执行SqlSession对象执行查询,获取结果User
6. 打印结果
7. 释放资源
public class MybatisTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void before() throws Exception {
// 1. 创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 2. 加载SqlMapConfig.xml配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 创建SqlSessionFactory对象
this.sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
}
@Test
public void testQueryUserById() throws Exception {
// 4. 创建SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 5. 执行SqlSession对象执行查询,获取结果User
// 第一个参数是User.xml的statement的id,第二个参数是执行sql需要的参数;
Object user = sqlSession.selectOne("test.queryUserById", 1);
// 6. 打印结果
System.out.println(user);
// 7. 释放资源
sqlSession.close();
}
}
通过名字模糊查询
查询sql:
SELECT * FROM `user` WHERE username LIKE '%马%'
user.xml配置
<select id="selectUserByName" parameterType="String" resultType="com.fdw.pojo.User">
SELECT * FROM t_user WHERE name like "%"#{name}"%"
</select>
测试
@Test
public void testQueryUserByUsername() throws Exception {
// 4. 创建SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 5. 执行SqlSession对象执行查询,获取结果User
// 查询多条数据使用selectList方法
List<Object> list = sqlSession.selectList("test.queryUserByUsername1", "马");
// 6. 打印结果
for (Object user : list) {
System.out.println(user);
}
// 7. 释放资源
sqlSession.close();
}
#{}和${}
#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换。#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。
parameterType和resultType
parameterType:指定输入参数类型,mybatis通过ognl从输入对象中获取参数值拼接在sql中。
resultType:指定输出结果类型,mybatis将sql查询结果的一行记录数据映射为resultType指定类型的对象。如果有多条数据,则分别进行映射,并把对象放到容器List中
selectOne和selectList
selectOne查询一条记录,如果使用selectOne查询多条记录则抛出异常
若是增删改的操作必须提交事务
增加用户
<insert id="addUser" parameterType="com.fdw.pojo.User">
insert into t_user (name,sex,address,balance)
values (#{name},#{sex},#{address},#{balance})
</insert>
-测试
@Test
public void testSaveUser() {
// 4. 创建SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 5. 执行SqlSession对象执行保存
// 创建需要保存的User
User user = new User();
user.setName("张飞");
user.setSex("1");
user.setAddress("蜀国");
sqlSession.insert("test.addUser", user);
System.out.println(user);
// 需要进行事务提交
sqlSession.commit();
// 7. 释放资源
sqlSession.close();
}
修改用户
<update id="updateUser" parameterType="com.fdw.pojo.User">
update t_user
set name = #{name},sex = #{sex},address = #{address},balance=#{balance},companyId=#{companyId}
where id = #{id}
</update>
测试
@Test
public void testUpdateUserById() {
// 4. 创建SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 5. 执行SqlSession对象执行更新
// 创建需要更新的User
User user = new User();
user.setId(26);
user.setName("关羽");
user.setSex("1");
user.setAddress("蜀国");
sqlSession.update("test.updateUser", user);
// 需要进行事务提交
sqlSession.commit();
// 7. 释放资源
sqlSession.close();
}
删除用户
<delete id="delUser" parameterType="Integer">
delete from t_user
where id = #{superman}
</delete>
测试
@Test
public void testDeleteUserById() {
// 4. 创建SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 5. 执行SqlSession对象执行删除
sqlSession.delete("test.delUser", 48);
// 需要进行事务提交
sqlSession.commit();
// 7. 释放资源
sqlSession.close();
}
Mybatis 与 hibernate 区别
Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句。mybatis可以通过XML或注解方式灵活配置要运行的sql语句,并将java对象和sql语句映射生成最终执行的sql,最后将sql执行的结果再映射生成java对象。
Mybatis学习门槛低,简单易学,程序员直接编写原生态sql,可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁,一但需求变化要求成果输出迅速。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。
Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件(例如需求固定的定制化软件)如果用hibernate开发可以节省很多代码,提高效率。但是Hibernate的学习门槛高,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡,以及怎样用好Hibernate需要具有很强的经验和能力才行。
总之,按照用户的需求在有限的资源环境下只要能做出维护性、扩展性良好的软件架构都是好架构,所以框架只有适合才是最好。
原始dao层开发
sqlSessionFactoryBuilder 读取配置文件 调用build方法
SqlSessionFactory 创建 sqlsession
Sqlsession 封装方法(每次都打开一个新的session)
Dao依赖于sqlSessionFactory
private SqlSessionFactory sqlSessionFactory;
public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
}
@Override
public User selectUserById(Integer id) {
SqlSession sqlSession = sqlSessionFactory.openSession();
return sqlSession.selectOne("test.selectUserById",id);
}
代理dao (mapper接口) 开发
前提条件
- 接口方法名 == User.xm 的id名
- 返回值类型 与(Mapper.xm) 映射文件类型返回值类型一致
- 方法的入参类型与 映射文件中入参数类型一致
- 命名空间绑定此接口(namespace值与接口相对路径名一致)
接口名字 建议与 配置文件名字保持一致
注意事项:方法中的参数就只能有一个
Selectone 与 selectList根据,mapper的返回值类型决定
SqlMapperConfig配置文件详解
配置文件属性顺序必须如上图一致
TypeAliases 别名
<typeAliases>
<typeAlias alias="User" type="com.fdw.pojo.User"></typeAlias>
<package name="com.fdw.pojo"></package>
</typeAliases>
Typehandlers 类型处理器
实现jdbc(数据库中的类型)和java类型的转换,一般不用自己去改,特殊情况下需要自己手动映射。
Properties 设置属性
Settings mybatis功能的设置
输入类型 和 输出类型
输入类型
普通类型
使用#{}占位符,或者${}进行sql拼接。
使用pojo类型
Mybatis使用ognl表达式解析对象字段的值,#{}或者${}括号中的值为pojo属性名称。
Pojo包装类 既包含普通类型也包含其他类型
包装对象:Pojo类中的一个属性是另外一个pojo。
输出类型
ResultType
自动装换(属性名 与数据库字段名一致)
ResultMap
手动转换 ,如果名字不一致则需要手动映射
<resultMap id="userxixi" type="com.fdw.pojo.User">
<result property="password" column="psd"></result>
</resultMap>
<select id="selectUserById" parameterType="QueryVo" resultMap="userxixi">
SELECT * FROM t_user WHERE id =#{id}
</select>
ResultMap: type 将要转换的类型
Id:主键 property实体类的属性名 column 数据库列的字段名
result 普通属性
动态sql
If标签
<if test="id != '' and id != null">
AND id =#{id}
</if>
<if test="name != '' and name != null">
AND name =#{name}
</if>
Test 使用ognl表达式的方式取值,可以if条件 并且and 或者 or
如果有多个条件,不知道是第一个成立and的位置不好放,放在任何一个位置都有可能有异常,使用where标签解决
Where标签 (自动去除前and)
若所有条件都不成立,那么where标签就去除
Foreach标签
<foreach collection="array" close=")" item="id" open="(" separator=",">
#{id}
</foreach>
Collection 识别数据类型
数组:array set集合:set
List集合:list 封装类:必须是封装类的属性名
<!-- item:遍历的元素,可以随便写,,但是和后面的#{}里面要一致 -->
<!-- open:在前面添加的sql片段 -->
<!-- close:在结尾处添加的sql片段 -->
<!-- separator:指定遍历的元素之间使用的分隔符 -->
Index 下标
SQL片段
<sql id="userFields">
id, username, birthday, sex, address
</sql>
SELECT <include refid="userFields" /> FROM `user`
Include refid 属性对应的就是 SQL片段的id名
多表查询
一对一
实现一对一查询的结果集封装
两种办法:
ResultType
新建一个实体类,这个实体类包含所有转换的列名
可以建一个类,让这个类去继承一个类
<mapper namespace="com.fdw.manyTables.UserMapper">
<select id="selectUser" resultType="com.fdw.manyTables.UserView">
SELECT
t_user.`name`,
t_user.sex,
t_user.address,
t_user.balance,
company.`name` AS companyname,
company.address AS companyaddress,
t_user.companyId,
t_user.id
FROM
t_user
LEFT JOIN company ON t_user.companyId = company.id
</select>
resultMap
在user实体类中增加一个引用类的属性,并添加get-set方法,在结果集处理时采用
resultMap
<resultMap id="userView" type="user">
<id property="id" column="id"></id>
<result property="address" column="address"></result>
<association property="company" javaType="company">
<id property="id" column="company"></id>
<result property="address" column="companyaddress"></result>
</association>
</resultMap>
若字段名和属性不写转换,就不会转化,要想将查询到的结果全部封装到实体类中,就必须全部都写
一对多
ResultType(不建议使用)
新建一个实体类,这个实体类包含所有转换的列名
可以建一个类,让这个类去继承一个类
ResultMap
添加属性 并添加get-set方法
<resultMap id="companyView" type="company">
<id property="id" column="companyId"></id>
<result property="name" column="companyName"></result>
<collection property="users" javaType="list" ofType="user">
<id property="id" column="id"></id>
<result property="name" column="name"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
</collection>
</resultMap>
Collection property实体类的属性名,javaType(集合list set)
ofType 封装集合中每个元素的类型
(以下三种技术 可了解)
缓存(Redis memache)
延迟加载
逆向工程
逆向工程,通过一方生成另一方