MyBatis本是apache的一个开源项目iBatis
SSM = Spring+SpringMVC+MyBatis
SSH= Spring+Struts+Hibernate
MyBatis 是一种优秀的持久层框架,它是一个基于 Java 的开源框架,用于简化数据库访问的开发。MyBatis 提供了灵活的映射方式,将对象与 SQL 语句进行映射,并提供了丰富的功能来处理数据库操作。
以下是 MyBatis 的特点和主要功能:
灵活的映射:MyBatis 使用 XML 或注解来定义对象与 SQL 语句之间的映射关系,可以方便地进行 CRUD 操作。
SQL 控制:MyBatis 允许开发者编写原生 SQL,可以更灵活地控制 SQL 语句的编写和优化。
参数绑定:MyBatis 支持将 Java 对象作为参数传递给 SQL 语句,通过占位符来进行参数绑定,可以有效避免 SQL 注入攻击。
自动映射:MyBatis 可以根据对象与表的命名规则自动进行属性到字段的映射,大大减少了手动编写映射的工作。
缓存支持:MyBatis 提供了一级缓存和二级缓存机制,可以加快数据访问效率。
多数据库支持:MyBatis 支持多种数据库,包括 MySQL、Oracle、SQL Server 等。
事务管理:MyBatis 可以通过配置开启事务管理,保证数据操作的一致性和完整性。
总的来说,MyBatis 提供了强大且灵活的数据库访问功能,能够帮助开发者更高效地进行数据库操作。它与 Spring 等框架集成使用,广泛应用于 Java 后端开发中。
sql语句写到了 daoimpl dao中 ,不利于系统的维护 sql写到了java代码中【硬编码】
解决方案: 将sql语句放到一个单独的文件中 【xml】
PreparedStatement 该对象需要处理问号 存在sql和java的硬编码问题
解决方案: 将sql和参数设置在 xml中
resultSet 进行遍历 使用列名或者序号获取数据 ,不利于系统的维护
解决方案: 将查询到的结果直接映射为 java对象
因为mybatis底层就是jdbc,使用mybatis的框架就可以解决上述问题。
https://mybatis.net.cn/
SqlMapConfig.xml 是 MyBatis 的核心配置文件,用于配置 MyBatis 的全局属性和资源引用。
在 SqlMapConfig.xml 文件中,可以进行以下配置:
数据源配置:通过 元素配置数据库连接池的相关信息,包括数据库驱动、连接 URL、用户名、密码等。
事务管理器配置:通过 元素配置事务管理器,可以选择使用 MyBatis 默认的 JDBC 事务管理器或使用第三方的事务管理器。
类型别名配置:通过 元素配置类型别名,可以为 Java 类或接口设置别名,简化 SQL 映射文件中类型的引用。
Mapper 文件配置:通过 元素配置 Mapper 文件的引入方式,可以使用 元素引入单个 Mapper 文件,也可以使用 元素批量引入一个包下的所有 Mapper 文件。
全局属性配置:通过 元素配置全局属性,可以在 MyBatis 的配置文件中定义一些全局通用的属性,供后续的配置项中引用。
除了上述常见的配置项外,SqlMapConfig.xml 还可以配置其他一些高级选项,例如插件、缓存配置、日志实现等。
以下是一个简单的 SqlMapConfig.xml 配置示例:
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydatabase"/>
<property name="username" value="root"/>
<property name="password" value="password"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="com/example/mapper/ExampleMapper.xml"/>
<package name="com.example.mapper"/>
mappers>
configuration>
以上示例配置了数据库连接池、事务管理器,引入了一个 Mapper 文件和一个包下的所有 Mapper 文件。
SqlMapConfig.xml 是 MyBatis 的主要配置文件之一,它提供了全局性的配置信息,为 MyBatis 的使用和功能扩展提供了基础。
会话工厂(SqlSessionFactory)是 MyBatis 的核心接口之一,用于创建 SqlSession 对象。在使用 MyBatis 进行数据库操作时,通常需要先创建会话工厂,然后通过会话工厂创建 SqlSession 对象,最终使用 SqlSession 对象进行数据库操作。
会话工厂的创建是一个比较耗时的操作,因此一般情况下一个应用只需要创建一个会话工厂即可,多个 SqlSession 实例可以共享同一个会话工厂。
MyBatis 提供了多种方式来创建会话工厂,其中常用的有以下两种:
使用 XML 配置文件方式创建会话工厂是 MyBatis 的传统方式,需要在配置文件中指定数据库连接信息、映射文件等。具体可以参考 MyBatis 的 SqlMapConfig.xml 配置文件。
示例代码:
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sessionFactory.openSession();
以上代码使用 org.apache.ibatis.io.Resources 类的 getResourceAsStream() 方法加载 MyBatis 的 XML 配置文件,然后通过 SqlSessionFactoryBuilder 类的 build() 方法创建会话工厂对象,最终使用 SqlSessionFactory 的 openSession() 方法获取 SqlSession 对象进行数据库操作。
MyBatis 也支持使用 Java 代码方式创建会话工厂,相对于 XML 配置文件更加灵活。可以通过编写 Java 类来创建会话工厂,直接指定数据库连接信息、映射文件等。
示例代码:
DataSource dataSource = getDataSource();
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(UserMapper.class);
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(configuration);
以上代码使用 javax.sql.DataSource 接口的实现类 getDataSource() 方法获取数据源对象,然后创建事务工厂、环境、配置对象,最终添加映射器并构建会话工厂对象。
总之,会话工厂是 MyBatis 中非常重要的核心组件,其创建方式决定了 MyBatis 的基本使用方式,需要根据项目的实际情况选择合适的创建方式。
MyBatis的DAO(Data Access Object)开发模式可以使用XML或注解两种方式来实现,下面我们将分别介绍这两种方式的基本用法。
在XML方式中,你需要编写一个Mapper XML文件,其中定义了一系列SQL语句,然后创建一个Mapper接口,与Mapper XML文件中定义的SQL语句相对应。以下是一个简单示例:
Mapper XML文件:
<mapper namespace="com.example.dao.UserMapper">
<select id="getUserById" resultType="com.example.entity.User">
SELECT * FROM user WHERE id = #{id}
select>
mapper>
Mapper接口:
// UserMapper.java
public interface UserMapper {
User getUserById(Integer id);
}
在上面的示例中,我们创建了一个名为UserMapper的Mapper接口,并定义了一个getUserById方法,该方法使用了id参数来执行数据库查询操作,并返回User对象作为查询结果。在Mapper XML文件中,我们定义了一条SELECT语句来查询符合条件的用户信息,resultType属性指定了查询结果的Java类型。
除了XML方式,MyBatis还支持注解方式来定义SQL语句和Mapper接口方法。以下是一个简单示例:
// UserMapper.java
@Mapper
public interface UserMapper {
@Select("SELECT * FROM user WHERE id = #{id}")
User getUserById(Integer id);
}
在上述示例中,我们在getUserById方法上使用了@Select注解来指定SQL语句。在@Select注解中,我们使用了${}占位符来表示查询条件。同时,我们还在UserMapper接口上使用了@Mapper注解,来告诉MyBatis该接口是一个Mapper接口。
无论是XML方式还是注解方式,都需要通过SqlSessionFactory创建SqlSession,然后通过SqlSession的getMapper方法来获取Mapper接口的实现,最终使用Mapper接口调用方法来执行对应的SQL语句。以下是一个示例代码:
// 创建SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获取Mapper接口实现
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 调用Mapper方法执行SQL语句
User user = userMapper.getUserById(1);
// 关闭SqlSession
sqlSession.close();
在示例代码中,我们首先通过mybatis-config.xml配置文件来创建一个SqlSessionFactory对象,然后通过SqlSessionFactory创建SqlSession对象。接着,我们通过SqlSession的getMapper方法来获取UserMapper接口的实现,最后调用Mapper方法来执行相应的SQL查询语句。执行完毕后,我们需要关闭SqlSession。
Mapper代理模式是MyBatis中一种简化Mapper接口实现的方式。通过Mapper代理模式,我们无需手动编写Mapper接口的实现类,而是由MyBatis框架动态生成Mapper接口的实现。
具体实现过程如下:
public interface UserMapper {
User getUserById(Integer id);
void insertUser(User user);
void updateUser(User user);
void deleteUser(Integer id);
}
<mapper namespace="com.example.dao.UserMapper">
<select id="getUserById" resultType="com.example.entity.User">
SELECT * FROM user WHERE id = #{id}
select>
<insert id="insertUser" parameterType="com.example.entity.User">
INSERT INTO user (id, name, age) VALUES (#{id}, #{name}, #{age})
insert>
mapper>
<configuration>
<mappers>
<mapper resource="com/example/dao/UserMapper.xml"/>
mappers>
configuration>
使用Mapper代理模式:在代码中,我们可以通过SqlSession的getMapper方法来获取Mapper接口的代理对象,并使用代理对象执行数据库操作。
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.getUserById(1);
user.setName("Alice");
userMapper.updateUser(user);
sqlSession.commit();
sqlSession.close();
在上述代码中,我们首先通过SqlSessionFactory
创建SqlSession
对象,然后通过getMapper
方法获取UserMapper接口的代理对象。通过代理对象,我们可以直接调用接口中定义的方法,例如getUserById()
和updateUser()
等。MyBatis框架会根据接口方法的名称和参数类型,在底层动态生成SQL语句并执行,完成与数据库的交互操作。
需要注意的是,Mapper代理模式要求Mapper接口和Mapper XML文件的名称、位置和命名空间(namespace)保持一致,这样MyBatis才能正确地将XML中的SQL语句与接口方法关联起来。
在mapper.xml中namespace等于 mapper接口地址
在mapper.xml中statementID要和 mapper接口中的方法名保持一致
//在mapper.xml中的resultType 要和 mapper.java中输出参数类型保持一致[返回值]
resultType=“com.liushao.entity.User” public List findAll();在mapper.xml中的parameterType 要和 mapper.java中输入参数类型保持一致[形参]
public List findAll(); 目前木有
一般多表查询的情况下要先确定主表
假设有一个用户表和一个订单表
然后写出sql语句
<select id="findouodi" resultMap="douodi">
SELECT
user.*,
orders.id or_id,
orders.user_id,
orders.number,
orders.createtime,
orders.note,
orderdetail.id ord_id,
orderdetail.orders_id,
orderdetail.items_id,
orderdetail.items_num,
items.id it_id,
items.name,
items.price,
items.detail
FROM
USER,
orders,
orderdetail,
items
WHERE user.`id`=orders.user_id
AND orders.`id`=orderdetail.`orders_id`
AND orderdetail.`items_id`=items.`id`
</select>
<resultMap id="douodi" type="entity.User">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
<collection property="ordersList" ofType="entity.Orders">
<id column="or_id" property="id"></id>
<result column="user_id" property="userId"></result>
<result column="number" property="number"></result>
<result column="createtime" property="createtime"></result>
<result column="note" property="note"></result>
<collection property="orderdetails" ofType="entity.Orderdetail">
<id column="ord_id" property="id" />
<result column="items_id" property="itemsId"/>
<result column="items_num" property="itemsNum"/>
<result column="orders_id" property="ordersId"/>
<association property="items" javaType="entity.Items" >
<id column="it_id" property="id"></id>
<result column="name" property="name"></result>
<result column="price" property="price"></result>
<result column="detail" property="detail"></result>
<result column="createtime" property="createtime"></result>
</association>
</collection>
</collection>
</resultMap>
测试
@Test
public void findUserListCount() {
SqlSession sqlSession = factory.openSession();
//获取代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> findouod = userMapper.findouodi();
System.out.println(findouod);
}
看下这个多表查询,这是一个多对多 查询四个表。
注意 每个表都有id 但是这个
标签这里的column一定要起别名 如果不起别名会与其他表的id冲突,就会导致出现意想不到的结果
而且这里实体类我是以User用户为主表来进行查询,那么User实体类中就要多加上Orders ,因为Orders表在数据库中又与Ordersdetail有联系,那么Orders中要加上Ordersdetail属性
依此类推得出最终的四个实体类
User类
package entity;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class User implements Serializable {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
private List<Orders> ordersList =new ArrayList<>();
public List<Orders> getOrdersList() {
return ordersList;
}
public void setOrdersList(List<Orders> ordersList) {
this.ordersList = ordersList;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
", ordersList=" + ordersList +
'}';
}
public User() {
}
public User(String username) {
this.username = username;
}
public User(Integer id, String username, Date birthday, String sex, String address) {
this.id = id;
this.username = username;
this.birthday = birthday;
this.sex = sex;
this.address = address;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
Orders实体类
package entity;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class Orders implements Serializable {
public Integer id;
public Integer userId;
public String number;
public Date createtime;
public String note;
@Override
public String toString() {
return "Orders{" +
"id=" + id +
", userId=" + userId +
", number='" + number + '\'' +
", createtime=" + createtime +
", note='" + note + '\'' +
", orderdetails=" + orderdetails +
'}';
}
//添加用户信息过来 用于使用 resultMap
//订单明细的集合
private List<Orderdetail> orderdetails= new ArrayList<>();
public List<Orderdetail> getOrderdetails() {
return orderdetails;
}
public void setOrderdetails(List<Orderdetail> orderdetails) {
this.orderdetails = orderdetails;
}
public Orders(Integer id, Integer userId, String number, Date createtime, String note) {
this.id = id;
this.userId = userId;
this.number = number;
this.createtime = createtime;
this.note = note;
}
public Orders() {}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public Date getCreatetime() {
return createtime;
}
public void setCreatetime(Date createtime) {
this.createtime = createtime;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}
Orderdetail实体类
package entity;
import java.io.Serializable;
import java.util.List;
public class Orderdetail implements Serializable {
private Integer id;
private Integer ordersId;
@Override
public String toString() {
return "Orderdetail{" +
"id=" + id +
", ordersId=" + ordersId +
", itemsId=" + itemsId +
", itemsNum=" + itemsNum +
", items=" + items +
'}';
}
private Integer itemsId;
private Integer itemsNum;
private Items items;
public Orderdetail(Integer id, Integer ordersId, Integer itemsId, Integer itemsNum) {
this.id = id;
this.ordersId = ordersId;
this.itemsId = itemsId;
this.itemsNum = itemsNum;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getOrdersId() {
return ordersId;
}
public void setOrdersId(Integer ordersId) {
this.ordersId = ordersId;
}
public Integer getItemsId() {
return itemsId;
}
public void setItemsId(Integer itemsId) {
this.itemsId = itemsId;
}
public Integer getItemsNum() {
return itemsNum;
}
public void setItemsNum(Integer itemsNum) {
this.itemsNum = itemsNum;
}
public Orderdetail() {
}
}
Items实体类
package entity;
import java.sql.Timestamp;
import java.util.Date;
public class Items {
private Integer id;
private String name;
private Float price;
private String detail;
private String pic;
private Timestamp createtime;
public Items() {
}
@Override
public String toString() {
return "Items{" +
"id=" + id +
", name='" + name + '\'' +
", price=" + price +
", detail='" + detail + '\'' +
", pic='" + pic + '\'' +
", createtime=" + createtime +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Float getPrice() {
return price;
}
public void setPrice(Float price) {
this.price = price;
}
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail;
}
public String getPic() {
return pic;
}
public void setPic(String pic) {
this.pic = pic;
}
public Timestamp getCreatetime() {
return createtime;
}
public void setCreatetime(Timestamp createtime) {
this.createtime = createtime;
}
}
增删改都要提交事务就会刷新缓存
如果开启两个会话进行查询相同的内容,如果第一个会话先结束了,第二个会话再进行查询,查询的结果就是相同对象,也就是第一个会话查询之后产生缓存,第二个会话在第一个会话结束后进行查询的就是缓存中的东西