惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
DataBreaches.Net
V
Vulnerabilities – Threatpost
C
CERT Recently Published Vulnerability Notes
Google DeepMind News
Google DeepMind News
GbyAI
GbyAI
Y
Y Combinator Blog
T
Threatpost
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Project Zero
Project Zero
Engineering at Meta
Engineering at Meta
MongoDB | Blog
MongoDB | Blog
MyScale Blog
MyScale Blog
Security Latest
Security Latest
T
Threat Research - Cisco Blogs
量子位
I
Intezer
Simon Willison's Weblog
Simon Willison's Weblog
C
Cybersecurity and Infrastructure Security Agency CISA
L
Lohrmann on Cybersecurity
L
LINUX DO - 最新话题
The Register - Security
The Register - Security
T
Tailwind CSS Blog
爱范儿
爱范儿
Google DeepMind News
Google DeepMind News
T
Troy Hunt's Blog
Stack Overflow Blog
Stack Overflow Blog
Cloudbric
Cloudbric
S
Secure Thoughts
The GitHub Blog
The GitHub Blog
T
The Blog of Author Tim Ferriss
L
LangChain Blog
Recorded Future
Recorded Future
小众软件
小众软件
www.infosecurity-magazine.com
www.infosecurity-magazine.com
T
Tor Project blog
人人都是产品经理
人人都是产品经理
F
Full Disclosure
O
OpenAI News
Webroot Blog
Webroot Blog
A
Arctic Wolf
TaoSecurity Blog
TaoSecurity Blog
P
Privacy & Cybersecurity Law Blog
Jina AI
Jina AI
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
雷峰网
雷峰网
Microsoft Security Blog
Microsoft Security Blog
H
Heimdal Security Blog
B
Blog RSS Feed
Vercel News
Vercel News

博客园 - 八爻老骥

Gradle模块化项目中使用了非模块化库的编译方法 系统架构一一前端技术 WPF下的RibbonApplicationMenu控件自定义 系统架构——多线程的应用 系统架构——前后端分离 为什么要学DirectX? D3D实战-在窗口中画一个三角形 - 八爻老骥 - 博客园 DirectX 入门1-初识DirectX Tool Kit DirectX 12 版 俄罗斯方块 WPF俄罗斯方块改进版 - 八爻老骥 - 博客园 【编程漫谈】用JAVA画多边形 【编程漫谈】单机与联机 往Angular应用程序中添加DevExtreme 【编程漫谈】程序的运行环境 创建DevExtreme应用程序 【编程漫谈】程序的运行流程 【编程漫谈】程序的进入与退出 【编程漫谈】Hello world! WPF实战俄罗斯方块
系统架构一一ORM的应用
八爻老骥 · 2020-05-08 · via 博客园 - 八爻老骥

在没有ORM的时代,我们直接从数据库中返回完整的数据集,然后通过键值对取出相应字段的数据,当然更要需要,取出的数据还要转换成编程语言相应的类型,再进行数据的操作。这种方式存储数据干脆直接,还可以利用Sql语句进行查询的优化,有些复杂的查询逻辑还可以编写成存储过程,充分利用数据库的性能,降低客户端的压力。

//ADO.NET示例
        string connectionString =
            "Data Source=(local);Initial Catalog=Northwind;"
            + "Integrated Security=true";

        // Provide the query string with a parameter placeholder.
        string queryString =
            "SELECT ProductID, UnitPrice, ProductName from dbo.products "
                + "WHERE UnitPrice > @pricePoint "
                + "ORDER BY UnitPrice DESC;";

        // Specify the parameter value.
        int paramValue = 5;

        // Create and open the connection in a using block. This
        // ensures that all resources will be closed and disposed
        // when the code exits.
        using (SqlConnection connection =
            new SqlConnection(connectionString))
        {
            // Create the Command and Parameter objects.
            SqlCommand command = new SqlCommand(queryString, connection);
            command.Parameters.AddWithValue("@pricePoint", paramValue);

            // Open the connection in a try/catch block.
            // Create and execute the DataReader, writing the result
            // set to the console window.
            try
            {
                connection.Open();
                SqlDataReader reader = command.ExecuteReader();
                while (reader.Read())
                {
                    Console.WriteLine("\t{0}\t{1}\t{2}",
                        reader[0], reader[1], reader[2]);
                }
                reader.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            Console.ReadLine();
        }
    }

但直接利用Sql返回数据的方式,有个最大的问题就是可读性太差。首先程序代码中有很多拼合SQL的代码,以及数据迭代的代码。因为没有限制,还可以一边查询,一边处理业务逻辑,数据库操作代码和客户端代码混合一起,数量一上来,就变成天书了。所以有聪明的人,就把一些比较通用的部分分离出来,比如构建一个DBHelper,把数据库连接部分单独拉出来,再提供一些通用的查询函数,微软的企业库就是一个比较典型的实现。但这样也只是可以稍微偷懒一点,事务上好控制点。

//利用EntLib返回一个数据集。
        Database db = DatabaseFactory.CreateDatabase("ConStr");
            string sql = "select * from Brand";
            DbCommand cmd = db.GetSqlStringCommand(sql);
 
            DataSet set = db.ExecuteDataSet(cmd);

后来有了J2EE框架,里边定义了各种Bean,有一种Bean叫Entity Bean,这个Entity Bean基本上跟数据库一一对应的,可序列化,可用于远程传递数据的无状态类。也就是说J2EE里边,要求事先将数据记录转换成存值的对象,再通过Session Bean(也就是Bussiness Object、BO)的调用返回数据的Copy,所有的数据库存取的代码,限制在了持久层(也就是DataAccess Layer,DataAccess Object、DAO),按照这种思维一起,应用程序的结构就很清晰了,代码的可读性也提升了,代码的可维护性也就增强了,然后就可以往系统中增加更多的功能了。

虽说数据库操作放在了持久层里,但数据对像的生成还是要程序员去写的,一个表有上百个字段,那你就得写上几倍于数据表字段数量的get/set,以前直接写Sql是根据需要来做Select的投影,需要什么就查什么,而现在则要全部做个映射,这个工作量可想而知还是不小的。于是有人把这部分操作弄成了一个独立的组件,开放出相应的接口给下游程序调用,当然目标是Sql无关的,带来的好处就是干净,少了很多数据库层面的拼装。

//EntityFramework的一个例子
    public abstract class QueryBase<T> : IQueryBase<T> where T : EntityBase
    {
        protected AppDataContext DataContext { get; set; }

        public List<T> FindByPage()
        {
            return DataContext.Set<T>().ToList();
        }
    }
    


对应的Sql

select * from T --T must be replaced by actual table name

ORM还有个特性就是实现数据库的无关性。上述Entity Framework的例子里,因为不需要写出Sql的具体实现,所以可以通过规范,使用不同的数据库驱动,实现同一套代码,在不同的数据库上运行。

在Setup.cs中设置数据库配置。


            services.AddDbContext<AppDataContext>(
                options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))
                );

在Jpa中指定数据库方言

	@Bean
	public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws IOException, PropertyVetoException, SQLException {
		LocalContainerEntityManagerFactoryBean efactory = new LocalContainerEntityManagerFactoryBean();
		efactory.setDataSource(dataSource());
		HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
		jpaVendorAdapter.setGenerateDdl(true);
		jpaVendorAdapter.setDatabase(Database.MYSQL);
		jpaVendorAdapter.setShowSql(true);
		
		efactory.setJpaVendorAdapter(jpaVendorAdapter);
		efactory.setPersistenceProviderClass(org.hibernate.jpa.HibernatePersistenceProvider.class);
		efactory.setPersistenceUnitName("test");
		efactory.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver());

		return efactory;
	}

ORM另一个目的就是就是数据操作面向对象话,消除了面向过程的Sql语句的干扰,编程语言就可以做许多神奇的事情来。比如springdata中,只需要定义接口,然后通过动态代码加上依赖注入的方式,就可以实现持久层的实现:

public interface AccountRepository extends JpaRepository<Account, String> {
	Account findByUsername(String username);
}

当然ORM也有很多不足,比如无形中增加了许多配置项,也增加了学习成本,查询性能上没法跟SQL相比,聚合查询不太容易实现等。